package com.lingyue.auth.service;

import com.lingyue.auth.dto.AuthResponse;
import com.lingyue.auth.dto.LoginRequest;
import com.lingyue.auth.dto.RegisterRequest;
import com.lingyue.auth.entity.Session;
import com.lingyue.auth.entity.User;
import com.lingyue.auth.repository.SessionRepository;
import com.lingyue.auth.repository.UserRepository;
import com.lingyue.common.exception.ServiceException;
import com.lingyue.common.constant.HttpStatus;
import com.lingyue.common.util.JwtUtil;
import com.lingyue.common.util.PasswordUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.util.UUID;

/**
 * 认证服务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AuthService {
    
    private final UserRepository userRepository;
    private final SessionRepository sessionRepository;
    private final UserService userService;
    
    @Value("${jwt.secret:lingyue-zhibao-secret-key-2024-please-change-in-production}")
    private String jwtSecret;
    
    @Value("${jwt.expiration:604800000}") // 7天，单位：毫秒
    private long jwtExpiration;
    
    @Value("${jwt.refresh-expiration:2592000000}") // 30天，单位：毫秒
    private long refreshExpiration;
    
    /**
     * 用户注册
     */
    @Transactional
    public AuthResponse register(RegisterRequest request) {
        // 验证密码确认
        if (!request.getPassword().equals(request.getConfirmPassword())) {
            throw new ServiceException("密码和确认密码不一致", HttpStatus.BAD_REQUEST);
        }
        
        // 检查用户名是否已存在
        com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<User> usernameWrapper = 
            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
        usernameWrapper.eq(User::getUsername, request.getUsername());
        if (userRepository.selectCount(usernameWrapper) > 0) {
            throw new ServiceException("用户名已存在", 422);
        }
        
        // 检查邮箱是否已存在
        com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<User> emailWrapper = 
            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
        emailWrapper.eq(User::getEmail, request.getEmail());
        if (userRepository.selectCount(emailWrapper) > 0) {
            throw new ServiceException("邮箱已被注册", 422);
        }
        
        // 创建用户
        User user = new User();
        user.setId(java.util.UUID.randomUUID().toString().replace("-", ""));
        user.setUsername(request.getUsername());
        user.setEmail(request.getEmail());
        user.setPasswordHash(PasswordUtil.encode(request.getPassword()));
        user.setRole("user");
        user.setCreateTime(new java.util.Date());
        userRepository.insert(user);
        
        log.info("User registered: {}", user.getUsername());
        
        // 生成Token并创建会话
        return createAuthResponse(user);
    }
    
    /**
     * 用户登录
     */
    @Transactional
    public AuthResponse login(LoginRequest request, String ipAddress, String userAgent) {
        // 查找用户（支持用户名或邮箱登录）
        com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<User> wrapper = 
            new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<>();
        wrapper.eq(User::getUsername, request.getUsernameOrEmail())
               .or()
               .eq(User::getEmail, request.getUsernameOrEmail());
        User user = userRepository.selectOne(wrapper);
        
        if (user == null) {
            throw new ServiceException("用户名或密码错误", HttpStatus.UNAUTHORIZED);
        }
        
        // 验证密码
        if (!PasswordUtil.matches(request.getPassword(), user.getPasswordHash())) {
            throw new ServiceException("用户名或密码错误", HttpStatus.UNAUTHORIZED);
        }
        
        // 更新最后登录时间
        user.setLastLoginAt(new java.util.Date());
        userRepository.updateById(user);
        
        log.info("User logged in: {}", user.getUsername());
        
        // 生成Token并创建会话
        AuthResponse response = createAuthResponse(user, ipAddress, userAgent);
        
        return response;
    }
    
    /**
     * 用户登出
     */
    @Transactional
    public void logout(String token) {
        String tokenHash = hashToken(token);
        Session session = sessionRepository.findByTokenHash(tokenHash);
        if (session != null) {
            sessionRepository.deleteById(session.getId());
        }
        log.info("User logged out");
    }
    
    /**
     * 刷新Token
     */
    @Transactional
    public AuthResponse refreshToken(String refreshToken) {
        String refreshTokenHash = hashToken(refreshToken);
        Session session = sessionRepository.findByRefreshTokenHash(refreshTokenHash);
        
        if (session == null) {
            throw new ServiceException("刷新Token无效", HttpStatus.UNAUTHORIZED);
        }
        
        // 检查Token是否过期
        if (session.getExpiresAt().before(new java.util.Date())) {
            sessionRepository.deleteById(session.getId());
            throw new ServiceException("刷新Token已过期", HttpStatus.UNAUTHORIZED);
        }
        
        // 获取用户
        User user = userService.getUserById(session.getUserId());
        if (user == null) {
            throw new ServiceException("用户不存在", HttpStatus.NOT_FOUND);
        }
        
        // 删除旧会话
        sessionRepository.deleteById(session.getId());
        
        // 创建新会话
        return createAuthResponse(user);
    }
    
    /**
     * 创建认证响应（包含Token和会话）
     */
    private AuthResponse createAuthResponse(User user) {
        return createAuthResponse(user, null, null);
    }
    
    /**
     * 创建认证响应（包含Token和会话）
     */
    private AuthResponse createAuthResponse(User user, String ipAddress, String userAgent) {
        // 生成Token
        String userId = user.getId().toString();
        String accessToken = JwtUtil.generateToken(userId, user.getUsername(), jwtSecret, jwtExpiration);
        String refreshToken = JwtUtil.generateRefreshToken(userId, user.getUsername(), jwtSecret);
        
        // 创建会话
        Session session = new Session();
        session.setId(java.util.UUID.randomUUID().toString().replace("-", ""));
        session.setUserId(user.getId());
        session.setTokenHash(hashToken(accessToken));
        session.setRefreshTokenHash(hashToken(refreshToken));
        java.util.Calendar cal = java.util.Calendar.getInstance();
        cal.add(java.util.Calendar.SECOND, (int)(jwtExpiration / 1000));
        session.setExpiresAt(cal.getTime());
        session.setIpAddress(ipAddress);
        session.setUserAgent(userAgent);
        session.setCreateTime(new java.util.Date());
        session.setLastUsedAt(new java.util.Date());
        sessionRepository.insert(session);
        
        // 构建响应
        AuthResponse response = new AuthResponse();
        response.setAccessToken(accessToken);
        response.setRefreshToken(refreshToken);
        response.setTokenType("Bearer");
        response.setExpiresIn(jwtExpiration / 1000);
        response.setUserId(user.getId());
        response.setUsername(user.getUsername());
        
        return response;
    }
    
    /**
     * 哈希Token（用于存储）
     */
    private String hashToken(String token) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(token.getBytes(StandardCharsets.UTF_8));
            StringBuilder hexString = new StringBuilder();
            for (byte b : hash) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) {
                    hexString.append('0');
                }
                hexString.append(hex);
            }
            return hexString.toString();
        } catch (Exception e) {
            throw new RuntimeException("Failed to hash token", e);
        }
    }
}

