package service

import (
	"context"
	"time"

	"hyapp/pkg/appcode"
	"hyapp/pkg/idgen"
	"hyapp/services/room-service/internal/room/command"
	"hyapp/services/room-service/internal/room/state"
)

const micDownReasonPublishTimeout = "publish_timeout"

// RunMicPublishTimeoutWorker 周期性释放超过 deadline 仍未确认 RTC 发流的麦位。
func (s *Service) RunMicPublishTimeoutWorker(ctx context.Context, interval time.Duration) {
	if interval <= 0 || s.micPublishTimeout <= 0 {
		// 非正数表示显式关闭，便于测试或临时止血。
		return
	}

	ticker := time.NewTicker(interval)
	defer ticker.Stop()

	for {
		select {
		case <-ctx.Done():
			return
		case <-ticker.C:
			_ = s.SweepMicPublishTimeouts(ctx)
		}
	}
}

// SweepMicPublishTimeouts 扫描本节点已装载 Room Cell，自动下掉未确认发流的 pending_publish 麦位。
func (s *Service) SweepMicPublishTimeouts(ctx context.Context) error {
	now := s.clock.Now()
	nowMs := now.UnixMilli()
	for _, roomRef := range s.loadedRoomRefs() {
		roomCtx := appcode.WithContext(ctx, roomRef.AppCode)
		lease, owned, err := s.loadedRoomLease(roomCtx, roomRef, now)
		if err != nil {
			return err
		}
		if !owned {
			continue
		}

		roomCell := s.loadCell(roomCtx, roomRef.RoomID)
		if roomCell == nil {
			continue
		}

		currentState, _, err := roomCell.Snapshot(roomCtx)
		if err != nil {
			return err
		}
		owned, err = s.verifyLoadedRoomLease(roomCtx, roomRef, lease, s.clock.Now())
		if err != nil {
			return err
		}
		if !owned {
			continue
		}

		for _, seat := range pendingPublishTimedOutSeats(currentState, nowMs) {
			owned, err = s.verifyLoadedRoomLease(roomCtx, roomRef, lease, s.clock.Now())
			if err != nil {
				return err
			}
			if !owned {
				break
			}

			cmd := command.MicDown{
				Base: command.Base{
					RequestID:     idgen.New("req_mic_publish_timeout"),
					CommandID:     idgen.New("cmd_mic_publish_timeout"),
					ActorID:       seat.UserID,
					Room:          roomRef.RoomID,
					GatewayNodeID: s.nodeID,
					SessionID:     "mic-publish-timeout",
					SentAtMS:      nowMs,
				},
				TargetUserID: seat.UserID,
				MicSessionID: seat.MicSessionID,
				Reason:       micDownReasonPublishTimeout,
			}
			if _, err := s.micDown(roomCtx, cmd); err != nil {
				return err
			}
		}
	}

	return nil
}

func pendingPublishTimedOutSeats(current *state.RoomState, nowMs int64) []state.MicSeat {
	if current == nil {
		return nil
	}

	seats := make([]state.MicSeat, 0)
	for _, seat := range current.MicSeats {
		if seat.UserID <= 0 || seat.MicSessionID == "" {
			continue
		}
		if seat.PublishState == state.MicPublishPending && seat.PublishDeadlineMS > 0 && seat.PublishDeadlineMS <= nowMs {
			// 返回值拷贝，后续 MicDown 还会用 mic_session_id 在当前 Cell 状态中二次校验。
			seats = append(seats, seat)
		}
	}

	return seats
}
