package gamerobot

import (
	"context"
	"strings"
	"time"

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	robotdomain "hyapp/services/robot-service/internal/domain/robot"
)

// Repository 是 game-robot 用例层的持久化边界；账号资料仍归 user-service，robot-service 只保存“可被当成机器人使用”的登记事实。
type Repository interface {
	PickGameRobot(ctx context.Context, appCode string, gameID string, excludeUserIDs []int64, nowMS int64) (robotdomain.Robot, error)
	ListGameRobots(ctx context.Context, appCode string, gameID string, status string, pageSize int32, cursor string) ([]robotdomain.Robot, string, error)
	RegisterGameRobots(ctx context.Context, appCode string, gameID string, userIDs []int64, adminID int64, nowMS int64) ([]robotdomain.Robot, error)
	SetGameRobotStatus(ctx context.Context, appCode string, gameID string, userID int64, status string, nowMS int64) (robotdomain.Robot, error)
	DeleteGameRobot(ctx context.Context, appCode string, userID int64) error
}

// Service 封装游戏机器人池的读取、登记和随机挑选逻辑；game-service 只通过 RPC 调用这里，不再直接操作机器人表。
type Service struct {
	repo Repository
	now  func() time.Time
}

func New(repo Repository) *Service {
	return &Service{repo: repo, now: time.Now}
}

func (s *Service) ListRobots(ctx context.Context, appCode string, gameID string, status string, pageSize int32, cursor string) ([]robotdomain.Robot, string, int64, error) {
	if s == nil || s.repo == nil {
		return nil, "", 0, xerr.New(xerr.Unavailable, "game robot repository is not configured")
	}
	app := appcode.Normalize(appCode)
	ctx = appcode.WithContext(ctx, app)
	items, next, err := s.repo.ListGameRobots(ctx, app, gameID, strings.TrimSpace(status), pageSize, cursor)
	return items, next, s.now().UnixMilli(), err
}

func (s *Service) RegisterRobots(ctx context.Context, appCode string, gameID string, userIDs []int64, adminID int64) ([]robotdomain.Robot, int64, error) {
	if s == nil || s.repo == nil {
		return nil, 0, xerr.New(xerr.Unavailable, "game robot repository is not configured")
	}
	if len(userIDs) == 0 {
		return nil, 0, xerr.New(xerr.InvalidArgument, "game robot user_ids is required")
	}
	app := appcode.Normalize(appCode)
	ctx = appcode.WithContext(ctx, app)
	nowMS := s.now().UnixMilli()
	items, err := s.repo.RegisterGameRobots(ctx, app, gameID, userIDs, adminID, nowMS)
	return items, nowMS, err
}

func (s *Service) PickRobot(ctx context.Context, appCode string, gameID string, matchID string, excludeUserIDs []int64, selectedAtMS int64) (robotdomain.Robot, int64, error) {
	if s == nil || s.repo == nil {
		return robotdomain.Robot{}, 0, xerr.New(xerr.Unavailable, "game robot repository is not configured")
	}
	if strings.TrimSpace(matchID) == "" {
		return robotdomain.Robot{}, 0, xerr.New(xerr.InvalidArgument, "game robot match_id is required")
	}
	app := appcode.Normalize(appCode)
	ctx = appcode.WithContext(ctx, app)
	nowMS := selectedAtMS
	if nowMS <= 0 {
		nowMS = s.now().UnixMilli()
	}
	item, err := s.repo.PickGameRobot(ctx, app, gameID, excludeUserIDs, nowMS)
	return item, nowMS, err
}

func (s *Service) SetRobotStatus(ctx context.Context, appCode string, gameID string, userID int64, status string) (robotdomain.Robot, int64, error) {
	if s == nil || s.repo == nil {
		return robotdomain.Robot{}, 0, xerr.New(xerr.Unavailable, "game robot repository is not configured")
	}
	if userID <= 0 {
		return robotdomain.Robot{}, 0, xerr.New(xerr.InvalidArgument, "game robot user_id is invalid")
	}
	app := appcode.Normalize(appCode)
	ctx = appcode.WithContext(ctx, app)
	nowMS := s.now().UnixMilli()
	item, err := s.repo.SetGameRobotStatus(ctx, app, gameID, userID, status, nowMS)
	return item, nowMS, err
}

func (s *Service) DeleteRobot(ctx context.Context, appCode string, userID int64) (int64, error) {
	if s == nil || s.repo == nil {
		return 0, xerr.New(xerr.Unavailable, "game robot repository is not configured")
	}
	if userID <= 0 {
		return 0, xerr.New(xerr.InvalidArgument, "game robot user_id is invalid")
	}
	app := appcode.Normalize(appCode)
	ctx = appcode.WithContext(ctx, app)
	nowMS := s.now().UnixMilli()
	return nowMS, s.repo.DeleteGameRobot(ctx, app, userID)
}
