package service

import (
	"context"
	"errors"
	"fmt"
	"strings"
	"time"

	"github.com/user-management-system/internal/auth"
	"github.com/user-management-system/internal/domain"
	"github.com/user-management-system/internal/pagination"
	"github.com/user-management-system/internal/repository"
)

// UserService 用户服务
type UserService struct {
	userRepo              *repository.UserRepository
	userRoleRepo          *repository.UserRoleRepository
	roleRepo              *repository.RoleRepository
	passwordHistoryRepo   *repository.PasswordHistoryRepository
}

const passwordHistoryLimit = 5 // 保留最近5条密码历史

// NewUserService 创建用户服务实例
func NewUserService(
	userRepo *repository.UserRepository,
	userRoleRepo *repository.UserRoleRepository,
	roleRepo *repository.RoleRepository,
	passwordHistoryRepo *repository.PasswordHistoryRepository,
) *UserService {
	return &UserService{
		userRepo:            userRepo,
		userRoleRepo:        userRoleRepo,
		roleRepo:            roleRepo,
		passwordHistoryRepo: passwordHistoryRepo,
	}
}

// ChangePassword 修改用户密码（含历史记录检查）
func (s *UserService) ChangePassword(ctx context.Context, userID int64, oldPassword, newPassword string) error {
	if s.userRepo == nil {
		return errors.New("user repository is not configured")
	}

	user, err := s.userRepo.GetByID(ctx, userID)
	if err != nil {
		return errors.New("用户不存在")
	}

	// 验证旧密码
	if strings.TrimSpace(oldPassword) == "" {
		return errors.New("请输入当前密码")
	}
	if !auth.VerifyPassword(user.Password, oldPassword) {
		return errors.New("当前密码不正确")
	}

	// 检查新密码强度
	if strings.TrimSpace(newPassword) == "" {
		return errors.New("新密码不能为空")
	}
	if err := validatePasswordStrength(newPassword, 8, false); err != nil {
		return err
	}

	// 检查密码历史
	if s.passwordHistoryRepo != nil {
		histories, err := s.passwordHistoryRepo.GetByUserID(ctx, userID, passwordHistoryLimit)
		if err == nil && len(histories) > 0 {
			for _, h := range histories {
				if auth.VerifyPassword(h.PasswordHash, newPassword) {
					return errors.New("新密码不能与最近5次密码相同")
				}
			}
		}

		// 保存新密码到历史记录
		newHashedPassword, hashErr := auth.HashPassword(newPassword)
		if hashErr != nil {
			return errors.New("密码哈希失败")
		}

		// #nosec G118 - 使用带超时的独立 context（不能使用请求 ctx，该 goroutine 在请求完成后仍可能运行）
		go func() { // #nosec G118
			bgCtx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
			defer cancel()
			_ = s.passwordHistoryRepo.Create(bgCtx, &domain.PasswordHistory{
				UserID:       userID,
				PasswordHash: newHashedPassword,
			})
			_ = s.passwordHistoryRepo.DeleteOldRecords(bgCtx, userID, passwordHistoryLimit)
		}()
	}

	// 更新密码
	newHashedPassword, err := auth.HashPassword(newPassword)
	if err != nil {
		return errors.New("密码哈希失败")
	}
	user.Password = newHashedPassword
	return s.userRepo.Update(ctx, user)
}

// GetByID 根据ID获取用户
func (s *UserService) GetByID(ctx context.Context, id int64) (*domain.User, error) {
	return s.userRepo.GetByID(ctx, id)
}

// GetByEmail 根据邮箱获取用户
func (s *UserService) GetByEmail(ctx context.Context, email string) (*domain.User, error) {
	return s.userRepo.GetByEmail(ctx, email)
}

// Create 创建用户
func (s *UserService) Create(ctx context.Context, user *domain.User) error {
	return s.userRepo.Create(ctx, user)
}

// Update 更新用户
func (s *UserService) Update(ctx context.Context, user *domain.User) error {
	return s.userRepo.Update(ctx, user)
}

// Delete 删除用户
func (s *UserService) Delete(ctx context.Context, id int64) error {
	return s.userRepo.Delete(ctx, id)
}

// List 获取用户列表
func (s *UserService) List(ctx context.Context, offset, limit int) ([]*domain.User, int64, error) {
	return s.userRepo.List(ctx, offset, limit)
}

// ListCursorRequest 用户游标分页请求
type ListCursorRequest struct {
	Keyword     string `form:"keyword"`
	Status      int    `form:"status"` // -1=全部
	RoleIDs     []int64
	CreatedFrom *time.Time
	CreatedTo   *time.Time
	SortBy      string // created_at, last_login_time, username
	SortOrder   string // asc, desc
	Cursor      string `form:"cursor"`
	Size        int    `form:"size"`
}

// ListCursor 游标分页获取用户列表（推荐使用）
func (s *UserService) ListCursor(ctx context.Context, req *ListCursorRequest) (*CursorResult, error) {
	size := pagination.ClampPageSize(req.Size)

	cursor, err := pagination.Decode(req.Cursor)
	if err != nil {
		return nil, fmt.Errorf("invalid cursor: %w", err)
	}

	filter := &repository.AdvancedFilter{
		Keyword:       req.Keyword,
		Status:        req.Status,
		RoleIDs:       req.RoleIDs,
		CreatedFrom:   req.CreatedFrom,
		CreatedTo:     req.CreatedTo,
		SortBy:        req.SortBy,
		SortOrder:     req.SortOrder,
	}

	users, hasMore, err := s.userRepo.ListCursor(ctx, filter, size, cursor)
	if err != nil {
		return nil, err
	}

	nextCursor := ""
	if len(users) > 0 {
		last := users[len(users)-1]
		nextCursor = pagination.BuildNextCursor(last.ID, last.CreatedAt)
	}

	return &CursorResult{
		Items:      users,
		NextCursor: nextCursor,
		HasMore:    hasMore,
		PageSize:   size,
	}, nil
}

// UpdateStatus 更新用户状态
func (s *UserService) UpdateStatus(ctx context.Context, id int64, status domain.UserStatus) error {
	return s.userRepo.UpdateStatus(ctx, id, status)
}

// BatchUpdateStatusRequest 批量更新状态请求
type BatchUpdateStatusRequest struct {
	IDs    []int64            `json:"ids" binding:"required,min=1"`
	Status domain.UserStatus   `json:"status" binding:"required"`
}

// BatchDeleteRequest 批量删除请求
type BatchDeleteRequest struct {
	IDs []int64 `json:"ids" binding:"required,min=1"`
}

// BatchUpdateStatus 批量更新用户状态
func (s *UserService) BatchUpdateStatus(ctx context.Context, req *BatchUpdateStatusRequest) (int64, error) {
	err := s.userRepo.BatchUpdateStatus(ctx, req.IDs, req.Status)
	return int64(len(req.IDs)), err
}

// BatchDelete 批量删除用户
func (s *UserService) BatchDelete(ctx context.Context, req *BatchDeleteRequest) (int64, error) {
	err := s.userRepo.BatchDelete(ctx, req.IDs)
	return int64(len(req.IDs)), err
}
