package service

import (
	"regexp"
	"time"

	"metazone.cc/metalab/internal/common"
	"metazone.cc/metalab/internal/model"

	"golang.org/x/crypto/bcrypt"
	"gorm.io/gorm"
)

var pwLower = regexp.MustCompile(`[a-z]`)
var pwUpper = regexp.MustCompile(`[A-Z]`)
var pwDigit = regexp.MustCompile(`\d`)

// dummyHash 防时序攻击：当用户不存在时，仍对虚拟哈希执行完整的 bcrypt 比对
var dummyHash []byte

func init() {
	hash, err := bcrypt.GenerateFromPassword([]byte("metazone-dummy-hash-2026"), 12)
	if err != nil {
		panic("failed to generate bcrypt dummy hash: " + err.Error())
	}
	dummyHash = hash
}

// validatePassword 密码强度：至少 8 位 + 包含大写字母 + 包含小写字母 + 包含数字
func validatePassword(pw string) error {
	if len(pw) < 8 || !pwLower.MatchString(pw) || !pwUpper.MatchString(pw) || !pwDigit.MatchString(pw) {
		return common.ErrWeakPassword
	}
	return nil
}

// ChangePassword 修改密码
// 流程：验证当前密码 → 校验新密码强度 → 哈希 → 更新 → 删除所有 session（强制重新登录）
func (s *AuthService) ChangePassword(userID uint, currentPassword, newPassword string) error {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return common.ErrUserNotFound
	}

	if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(currentPassword)) != nil {
		return common.ErrIncorrectPassword
	}

	if err := validatePassword(newPassword); err != nil {
		return err
	}

	hash, err := common.HashPassword(newPassword, s.cfg.Bcrypt.Cost)
	if err != nil {
		return err
	}

	user.PasswordHash = hash
	if err := s.userRepo.Update(user); err != nil {
		return err
	}

	// 删除所有 session，强制所有设备重新登录
	return s.invalidateSessions(userID)
}

// DeleteAccount 用户自主注销
func (s *AuthService) DeleteAccount(userID uint, password, reason string) error {
	user, err := s.userRepo.FindByID(userID)
	if err != nil {
		return common.ErrUserNotFound
	}

	if user.Role == model.RoleOwner {
		return common.ErrOwnerCannotDelete
	}

	if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)) != nil {
		return common.ErrIncorrectPassword
	}

	user.Status = model.StatusDeleted
	user.DeleteReason = reason

	if err := s.userRepo.Update(user); err != nil {
		return err
	}

	return s.invalidateSessions(userID)
}

// invalidateSessions 销毁某用户的所有 session（内部方法）
func (s *AuthService) invalidateSessions(userID uint) error {
	return s.sessionManager.DestroyByUID(userID)
}

// InvalidateSessions 公开方法：销毁用户所有 session（供 admin 等外部调用）
func (s *AuthService) InvalidateSessions(userID uint) error {
	return s.sessionManager.DestroyByUID(userID)
}

// ConfirmRestore 二次确认恢复已注销账号
func (s *AuthService) ConfirmRestore(req model.LoginRequest, loginIP string) (*model.User, error) {
	user, err := s.userRepo.FindByEmail(req.Email)
	if err != nil {
		_ = bcrypt.CompareHashAndPassword(dummyHash, []byte(req.Password))
		return nil, common.ErrInvalidCred
	}

	if user.Status != model.StatusDeleted {
		return nil, common.ErrUserNotFound
	}

	if bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password)) != nil {
		return nil, common.ErrInvalidCred
	}

	// 恢复账号
	user.Status = model.StatusActive
	user.DeletedAt = gorm.DeletedAt{}
	now := time.Now()
	user.LastLoginIP = loginIP
	user.LastLoginAt = &now
	if err := s.userRepo.Update(user); err != nil {
		return nil, err
	}

	return user, nil
}
