package service

import (
	"errors"

	"fmt"

	"time"

	"licserver/internal/model"

	"licserver/internal/utils"

	"golang.org/x/crypto/bcrypt"

	"gorm.io/gorm"

	"github.com/golang-jwt/jwt/v5"

	"github.com/mojocn/base64Captcha"
)

type UserService struct {
	db             *gorm.DB
	config         *utils.Config
	captchaService *CaptchaService
}

type UserProfile struct {
	ID       uint   `json:"id"`
	Username string `json:"username"`
	Email    string `json:"email"`
	Role     string `json:"role"`
}

// LoginInput 登录输入
type LoginInput struct {
	Username  string `json:"username" binding:"required"`
	Password  string `json:"password" binding:"required"`
	CaptchaId string `json:"captchaId" binding:"required"`
	Captcha   string `json:"captcha" binding:"required"`
}

func NewUserService(db *gorm.DB, config *utils.Config) *UserService {
	return &UserService{
		db:             db,
		config:         config,
		captchaService: NewCaptchaService(db, &config.Email),
	}
}

func (s *UserService) Register(username, password, email, captcha string) error {
	// 验证验证码
	if err := s.captchaService.VerifyCaptcha(email, "register", captcha); err != nil {
		return err
	}

	// 检查用户名是否已存在
	var count int64
	s.db.Model(&model.User{}).Where("username = ?", username).Count(&count)
	if count > 0 {
		return errors.New("用户名已存在")
	}

	// 检查邮箱是否已存在
	s.db.Model(&model.User{}).Where("email = ?", email).Count(&count)
	if count > 0 {
		return errors.New("邮箱已被注册")
	}

	// 原有的注册逻辑
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}

	user := model.User{
		Username: username,
		Password: string(hashedPassword),
		Email:    email,
		Role:     "user",
	}

	return s.db.Create(&user).Error
}

func (s *UserService) Login(username, password string) (string, error) {
	var user model.User
	if err := s.db.Where("username = ?", username).First(&user).Error; err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return "", errors.New("用户不存在")
		}
		return "", err

	}
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
		return "", errors.New("密码错误")
	}

	// 生成 JWT token
	token, err := utils.GenerateToken(user.ID, user.Username, user.Role, &s.config.JWT)
	if err != nil {
		return "", err
	}

	// 更新最后登录时间
	s.db.Model(&user).Update("last_login", gorm.Expr("CURRENT_TIMESTAMP"))
	return token, nil

}

func (s *UserService) GetUserByID(id uint) (*UserProfile, error) {
	var user model.User
	if err := s.db.First(&user, id).Error; err != nil {
		return nil, err
	}
	return &UserProfile{
		ID:       user.ID,
		Username: user.Username,
		Email:    user.Email,
		Role:     user.Role,
	}, nil

}

func (s *UserService) UpdateProfile(userID uint, email string) error {
	// 检查邮箱是否被其他用户使用
	var count int64
	if err := s.db.Model(&model.User{}).Where("email = ? AND id != ?", email, userID).Count(&count).Error; err != nil {
		return err
	}
	if count > 0 {
		return errors.New("邮箱已被其他用户使用")
	}

	// 更新用户信息
	return s.db.Model(&model.User{}).Where("id = ?", userID).Update("email", email).Error
}

func (s *UserService) ChangePassword(userID uint, oldPassword, newPassword string) error {
	var user model.User
	if err := s.db.First(&user, userID).Error; err != nil {
		return err
	}

	// 验证旧密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(oldPassword)); err != nil {
		return errors.New("旧密码错误")
	}

	// 加密新密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		return err
	}
	return s.db.Model(&user).Update("password", string(hashedPassword)).Error
}

func (s *UserService) ResetPassword(email, captcha string) error {
	// 验证验证码
	if err := s.captchaService.VerifyCaptcha(email, "reset", captcha); err != nil {
		return err
	}

	// 原有的重置密码逻辑
	var user model.User
	if err := s.db.Where("email = ?", email).First(&user).Error; err != nil {
		return errors.New("邮箱不存在")
	}

	// 生成重置令牌
	token, err := utils.GenerateResetToken()
	if err != nil {
		return err
	}

	// 保存重置令牌
	resetToken := model.PasswordResetToken{
		UserID:    user.ID,
		Token:     token,
		ExpiresAt: time.Now().Add(24 * time.Hour),
		Used:      false,
	}
	if err := s.db.Create(&resetToken).Error; err != nil {
		return err
	}

	// 发送重置邮件
	emailService := utils.NewEmailService(&s.config.Email)
	resetLink := fmt.Sprintf("http://localhost:%s/reset-password?token=%s", s.config.Server.Port, token)
	emailBody := fmt.Sprintf(`
		<h3>密码重置</h3>
		<p>您好，%s</p>
		<p>请点击以下链接重置您的密码：</p>
		<p><a href="%s">重置密码</a></p>
		<p>此链接将在24小时后失效。</p>
		<p>如果您没有请求重置密码，请忽略此邮件。</p>
	`, user.Username, resetLink)
	return emailService.SendEmail(user.Email, "密码重置", emailBody)

}

func (s *UserService) ValidateResetToken(token string) (*model.User, error) {
	var resetToken model.PasswordResetToken
	if err := s.db.Where("token = ? AND used = ? AND expires_at > ?",
		token, false, time.Now()).First(&resetToken).Error; err != nil {
		return nil, errors.New("无效或已过期的重置令牌")
	}

	var user model.User
	if err := s.db.First(&user, resetToken.UserID).Error; err != nil {
		return nil, err
	}
	return &user, nil

}

func (s *UserService) ResetPasswordWithToken(token, newPassword string) error {
	user, err := s.ValidateResetToken(token)
	if err != nil {
		return err
	}

	// 更新密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
	if err != nil {
		return err
	}

	// 使用事务确保原子性
	return s.db.Transaction(func(tx *gorm.DB) error {

		if err := tx.Model(&user).Update("password", string(hashedPassword)).Error; err != nil {
			return err
		}
		// 标记令牌为已使用
		if err := tx.Model(&model.PasswordResetToken{}).
			Where("token = ?", token).
			Update("used", true).Error; err != nil {
			return err
		}
		return nil
	})
}

func (s *UserService) SendRegisterCaptcha(email string) error {
	// 检查邮箱是否已被注册
	var count int64
	s.db.Model(&model.User{}).Where("email = ?", email).Count(&count)
	if count > 0 {
		return errors.New("邮箱已被注册")
	}

	return s.captchaService.SendEmailCaptcha(email, "register")
}

func (s *UserService) SendResetPasswordCaptcha(email string) error {
	var user model.User
	if err := s.db.Where("email = ?", email).First(&user).Error; err != nil {
		return errors.New("邮箱不存在")
	}

	return s.captchaService.SendEmailCaptcha(email, "reset")
}

func (s *UserService) GetCaptchaService() *CaptchaService {
	return s.captchaService
}

// GetUsers 获取用户列表
func (s *UserService) GetUsers(username, role string, page, pageSize int) ([]UserProfile, int64, error) {
	var users []model.User
	var total int64
	var profiles []UserProfile

	query := s.db.Model(&model.User{})

	if username != "" {
		query = query.Where("username LIKE ?", "%"+username+"%")
	}
	if role != "" {
		query = query.Where("role = ?", role)
	}

	// 获取总数
	query.Count(&total)

	// 分页查询
	if page > 0 && pageSize > 0 {
		offset := (page - 1) * pageSize
		query = query.Offset(offset).Limit(pageSize)
	}

	if err := query.Find(&users).Error; err != nil {
		return nil, 0, err
	}

	// 转换为 UserProfile
	for _, user := range users {
		profiles = append(profiles, UserProfile{
			ID:       user.ID,
			Username: user.Username,
			Email:    user.Email,
			Role:     user.Role,
		})
	}

	return profiles, total, nil
}

// CreateUser 创建新用户
func (s *UserService) CreateUser(username, password, email, role string) error {
	// 检查用户名是否已存在
	var count int64
	s.db.Model(&model.User{}).Where("username = ?", username).Count(&count)
	if count > 0 {
		return errors.New("用户名已存在")
	}

	// 检查邮箱是否已存在
	s.db.Model(&model.User{}).Where("email = ?", email).Count(&count)
	if count > 0 {
		return errors.New("邮箱已被注册")
	}

	// 加密密码
	hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	if err != nil {
		return err
	}

	user := model.User{
		Username: username,
		Password: string(hashedPassword),
		Email:    email,
		Role:     role,
	}

	return s.db.Create(&user).Error
}

// UpdateUser 更新用户信息
func (s *UserService) UpdateUser(id uint, email, role string) error {
	// 检查邮箱是否被其他用户使用
	var count int64
	s.db.Model(&model.User{}).Where("email = ? AND id != ?", email, id).Count(&count)
	if count > 0 {
		return errors.New("邮箱已被其他用户使用")
	}

	return s.db.Model(&model.User{}).Where("id = ?", id).Updates(map[string]interface{}{
		"email": email,
		"role":  role,
	}).Error
}

// DeleteUser 删除用户
func (s *UserService) DeleteUser(id uint) error {
	// 检查是否为最后一个管理员
	var adminCount int64
	s.db.Model(&model.User{}).Where("role = ?", "admin").Count(&adminCount)

	var user model.User
	if err := s.db.First(&user, id).Error; err != nil {
		return err
	}

	if user.Role == "admin" && adminCount <= 1 {
		return errors.New("不能删除最后一个管理员")
	}

	return s.db.Delete(&model.User{}, id).Error
}

// ValidateUser 验证用户名密码
func (s *UserService) ValidateUser(username, password string) (*model.User, error) {
	var user model.User
	if err := s.db.Where("username = ?", username).First(&user).Error; err != nil {
		return nil, errors.New("用户不存在")
	}

	// 使用 bcrypt 比较密码
	if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil {
		return nil, errors.New("密码错误")
	}

	return &user, nil
}

// GenerateToken 生成JWT token
func (s *UserService) GenerateToken(user *model.User) (string, error) {
	claims := jwt.MapClaims{
		"user_id":  user.ID,
		"username": user.Username,
		"role":     user.Role,
		"exp":      time.Now().Add(time.Hour * 24).Unix(), // 24小时过期
	}

	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(s.config.JWT.Secret))
}

// VerifyCaptcha 验证验证码
func (s *UserService) VerifyCaptcha(captchaId, captcha string) bool {
	return base64Captcha.DefaultMemStore.Verify(captchaId, captcha, true)
}
