package com.test.bijihoudaun.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.test.bijihoudaun.bo.UpdatePasswordBo;
import com.test.bijihoudaun.common.exception.BusinessException;
import com.test.bijihoudaun.common.exception.RegistrationException;
import com.test.bijihoudaun.entity.User;
import com.test.bijihoudaun.mapper.UserMapper;
import com.test.bijihoudaun.service.UserService;
import com.test.bijihoudaun.util.JwtTokenUtil;
import com.test.bijihoudaun.util.LoginLockUtil;
import com.test.bijihoudaun.util.PasswordUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;

@Service
@Transactional
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService, UserDetailsService {

    private static final int MIN_USERNAME_LENGTH = 2;
    private static final int MAX_USERNAME_LENGTH = 20;
    private static final int MIN_PASSWORD_LENGTH = 6;
    private static final int MAX_PASSWORD_LENGTH = 128;

    @Autowired
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        User user = userMapper.findByUsername(username);
        if (ObjectUtil.isNull(user)) {
            throw new UsernameNotFoundException("User not found with username: " + username);
        }
        // 加载用户角色权限
        java.util.List<GrantedAuthority> authorities = new ArrayList<>();
        String role = user.getRole();
        if (role == null || role.isEmpty()) {
            role = "USER"; // 默认角色
        }
        authorities.add(new SimpleGrantedAuthority("ROLE_" + role.toUpperCase()));
        return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities);
    }

    @Override
    public User register(String username, String password, String email) {
        if (username == null || username.trim().isEmpty()) {
            throw new RegistrationException("用户名不能为空");
        }
        username = username.trim();
        if (username.length() < MIN_USERNAME_LENGTH || username.length() > MAX_USERNAME_LENGTH) {
            throw new RegistrationException("用户名长度必须在" + MIN_USERNAME_LENGTH + "-" + MAX_USERNAME_LENGTH + "位之间");
        }
        
        if (password == null || password.isEmpty()) {
            throw new RegistrationException("密码不能为空");
        }
        if (password.length() < MIN_PASSWORD_LENGTH || password.length() > MAX_PASSWORD_LENGTH) {
            throw new RegistrationException("密码长度必须在" + MIN_PASSWORD_LENGTH + "-" + MAX_PASSWORD_LENGTH + "位之间");
        }
        
        String encrypt = PasswordUtils.encrypt(password);
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getUsername, username);
        if (this.count(queryWrapper) > 0) {
            throw new RegistrationException("用户名已存在");
        }
        queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getEmail, email);
        if (this.count(queryWrapper) > 0) {
            throw new RegistrationException("电子邮箱已被注册");
        }
        User user = new User();
        user.setUsername(username);
        user.setPassword(encrypt);
        user.setEmail(email);
        user.setRole("USER"); // 设置默认角色
        userMapper.insert(user);
        return user;
    }

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Override
    public String login(String username, String password) {
        // 检查账号是否被锁定
        if (LoginLockUtil.isLocked(username)) {
            long remainingSeconds = LoginLockUtil.getRemainingLockTime(username);
            throw new BadCredentialsException("账号已被锁定，请" + (remainingSeconds / 60 + 1) + "分钟后重试");
        }

        try {
            UserDetails userDetails = loadUserByUsername(username);
            if (!PasswordUtils.verify(password, userDetails.getPassword())) {
                // 记录登录失败
                LoginLockUtil.recordFailedAttempt(username);
                int remainingAttempts = LoginLockUtil.getRemainingAttempts(username);
                if (remainingAttempts <= 0) {
                    throw new BadCredentialsException("登录失败次数过多，账号已被锁定30分钟");
                }
                throw new BadCredentialsException("登录失败，请稍后重试");
            }

            // 登录成功，清除失败记录
            LoginLockUtil.recordSuccess(username);
            return jwtTokenUtil.generateToken(userDetails);
        } catch (UsernameNotFoundException e) {
            // 用户名不存在也记录失败（防止用户名枚举攻击）
            LoginLockUtil.recordFailedAttempt(username);
            throw new BadCredentialsException("用户名或密码错误");
        }
    }

    @Override
    public void deleteUser(Long id) {
        userMapper.deleteById(id);
    }

    @Override
    public Boolean isTokenExpired(Long id, String token) {
        LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(User::getId, id)
                .eq(User::getToken, token);
        User user = getOne(queryWrapper);
        return ObjectUtil.isNotNull(user) && new Date().before(user.getTokenEnddata());
    }

    @Override
    public void updatePassword(Long userId, UpdatePasswordBo updatePasswordBo) {
        User user = getById(userId);
        if (ObjectUtil.isNull(user)) {
            throw new BusinessException("用户不存在");
        }

        String newPassword = updatePasswordBo.getNewPassword();
        if (newPassword == null || newPassword.isEmpty()) {
            throw new BusinessException("新密码不能为空");
        }
        if (newPassword.length() < MIN_PASSWORD_LENGTH || newPassword.length() > MAX_PASSWORD_LENGTH) {
            throw new BusinessException("密码长度必须在" + MIN_PASSWORD_LENGTH + "-" + MAX_PASSWORD_LENGTH + "位之间");
        }

        if (!PasswordUtils.verify(updatePasswordBo.getOldPassword(), user.getPassword())) {
            throw new BusinessException("旧密码不正确");
        }

        if (PasswordUtils.verify(newPassword, user.getPassword())) {
            throw new BusinessException("新密码不能与旧密码相同");
        }

        user.setPassword(PasswordUtils.encrypt(newPassword));
        updateById(user);
    }
}