// Package roomtime runs room presence outbox consumers and exposes in-room duration compensation.
package roomtime

import (
	"context"
	"time"

	"hyapp/pkg/xerr"
	roomtimedomain "hyapp/services/user-service/internal/domain/roomtime"
)

// Repository applies room presence events and compensates abnormal open sessions.
type Repository interface {
	ProcessRoomPresenceEvent(ctx context.Context, event roomtimedomain.RoomPresenceEvent) (roomtimedomain.ApplyResult, error)
	CompensateOpenSessions(ctx context.Context, options roomtimedomain.CompensationOptions) (roomtimedomain.CompensationResult, error)
}

// Service owns the user in-room duration read model.
type Service struct {
	repository Repository
}

// CompensationWorkerOptions controls abnormal open session closure.
type CompensationWorkerOptions struct {
	WorkerID          string
	BatchSize         int
	OpenSessionMaxAge time.Duration
}

// New creates a room time service with the repository that owns idempotent application.
func New(repository Repository) *Service {
	return &Service{repository: repository}
}

// ConsumeRoomPresenceEvent applies one MQ-delivered RoomUserJoined/RoomUserLeft/RoomUserKicked fact.
func (s *Service) ConsumeRoomPresenceEvent(ctx context.Context, event roomtimedomain.RoomPresenceEvent) (roomtimedomain.ApplyResult, error) {
	if s == nil || s.repository == nil {
		return roomtimedomain.ApplyResult{}, xerr.New(xerr.Unavailable, "room time repository is not configured")
	}
	switch event.EventType {
	case roomtimedomain.RoomUserJoinedEventType, roomtimedomain.RoomUserLeftEventType, roomtimedomain.RoomUserKickedEventType:
	default:
		return roomtimedomain.ApplyResult{Skipped: true, Reason: "unsupported_event_type"}, nil
	}
	return s.repository.ProcessRoomPresenceEvent(ctx, event)
}

// ProcessOpenSessionCompensationBatch exposes one bounded compensation scan for cron-service.
func (s *Service) ProcessOpenSessionCompensationBatch(ctx context.Context, options CompensationWorkerOptions) (roomtimedomain.CompensationResult, error) {
	if s == nil || s.repository == nil {
		return roomtimedomain.CompensationResult{}, xerr.New(xerr.Unavailable, "room time repository is not configured")
	}
	if options.BatchSize <= 0 {
		options.BatchSize = 200
	}
	if options.OpenSessionMaxAge <= 0 {
		// stale worker 2 分钟内会把断线用户判离房；这里只兜 room-service 节点崩溃或 outbox 丢失的极端场景。
		options.OpenSessionMaxAge = 24 * time.Hour
	}
	return s.repository.CompensateOpenSessions(ctx, roomtimedomain.CompensationOptions{
		NowMs:               time.Now().UnixMilli(),
		BatchSize:           options.BatchSize,
		OpenSessionMaxAgeMs: options.OpenSessionMaxAge.Milliseconds(),
	})
}
