package com.example.demo.controller;

import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.example.demo.model.User;
import com.example.demo.model.SystemSettings;
import com.example.demo.model.UserMembership;
import com.example.demo.model.MembershipLevel;
import com.example.demo.service.RedisTokenService;
import com.example.demo.service.SystemSettingsService;
import com.example.demo.service.UserService;
import com.example.demo.service.VerificationCodeService;
import com.example.demo.util.JwtUtils;
import com.example.demo.util.UserIdGenerator;
import com.example.demo.repository.UserMembershipRepository;
import com.example.demo.repository.MembershipLevelRepository;

import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;

import java.time.LocalDateTime;
import java.util.Optional;

@RestController
@RequestMapping("/api/auth")
public class AuthApiController {
    
    private static final Logger logger = LoggerFactory.getLogger(AuthApiController.class);
    
    @Autowired
    private UserService userService;
    
    @Autowired
    private JwtUtils jwtUtils;
    
    @Autowired
    private VerificationCodeService verificationCodeService;
    
    @Autowired
    private RedisTokenService redisTokenService;
    
    @Autowired
    private SystemSettingsService systemSettingsService;
    
    @Autowired
    private UserMembershipRepository userMembershipRepository;
    
    @Autowired
    private MembershipLevelRepository membershipLevelRepository;
    
    /**
     * 用户登录（已禁用，仅支持邮箱验证码登录）
     * 为了向后兼容，保留此接口但返回提示信息
     */
    @PostMapping("/login")
    public ResponseEntity<Map<String, Object>> login(@RequestBody Map<String, String> credentials,
                                                    HttpServletRequest request,
                                                    HttpServletResponse response) {
        try {
            // 支持使用邮箱+密码登录（账号就是邮箱）或用户名+密码
            String emailOrUsername = credentials.get("email");
            if (emailOrUsername == null || emailOrUsername.trim().isEmpty()) {
                // 兼容旧客户端使用 username 字段
                emailOrUsername = credentials.get("username");
            }
            String password = credentials.get("password");

            if (emailOrUsername == null || emailOrUsername.trim().isEmpty() || password == null) {
                return ResponseEntity.badRequest().body(createErrorResponse("邮箱/用户名或密码不能为空"));
            }

            // 先尝试按邮箱查找用户
            com.example.demo.model.User user = userService.findByEmailOrNull(emailOrUsername);
            if (user == null) {
                // 再按用户名查找
                user = userService.findByUsernameOrNull(emailOrUsername);
            }

            if (user == null) {
                return ResponseEntity.badRequest().body(createErrorResponse("用户不存在"));
            }

            // 检查密码
            if (!userService.checkPassword(password, user.getPasswordHash())) {
                return ResponseEntity.badRequest().body(createErrorResponse("邮箱/用户名或密码不正确"));
            }
            
            // 检查用户是否被封禁
            if (user.getIsActive() == null || !user.getIsActive()) {
                return ResponseEntity.badRequest().body(createErrorResponse("您的账号已被封禁，请联系管理员"));
            }

            // 获取动态配置的过期时间（确保不为0或null，默认24小时）
            SystemSettings settings = systemSettingsService.getOrCreate();
            int expireHours = (settings.getTokenExpireHours() != null && settings.getTokenExpireHours() > 0) ? settings.getTokenExpireHours() : 24;
            long expireMs = expireHours * 60L * 60L * 1000L; // 转换为毫秒
            long expireSeconds = expireHours * 60L * 60L; // 转换为秒
            
            // 生成JWT Token（为了兼容系统中其他逻辑，使用 user.getUsername() 作为 token subject）
            logger.info("生成JWT: username={}, expireMs={}, expireHours={}", user.getUsername(), expireMs, expireHours);
            String token = jwtUtils.generateToken(user.getUsername(), user.getRole(), user.getId(), expireMs);
            
            // 验证刚生成的token是否有效
            try {
                java.util.Date expDate = jwtUtils.getExpirationDateFromToken(token);
                boolean isExpired = jwtUtils.isTokenExpired(token);
                logger.info("JWT验证: 过期时间={}, 当前时间={}, 是否过期={}", expDate, new java.util.Date(), isExpired);
            } catch (Exception e) {
                logger.error("JWT验证失败: {}", e.getMessage());
            }
            
            // 将 token 保存到 Redis
            redisTokenService.saveToken(user.getUsername(), token, expireSeconds);

            Map<String, Object> body = new HashMap<>();
            body.put("success", true);
            body.put("message", "登录成功");
            Map<String, Object> data = new HashMap<>();
            // 不返回密码哈希
            user.setPasswordHash(null);
            data.put("user", user);
            data.put("token", token);
            body.put("data", data);

            return ResponseEntity.ok(body);
        } catch (Exception e) {
            logger.error("用户名密码登录出错：", e);
            return ResponseEntity.badRequest().body(createErrorResponse("登录失败：" + e.getMessage()));
        }
    }
    
    /**
     * 验证码登录（邮箱）
     */
    @PostMapping("/login/email")
    public ResponseEntity<Map<String, Object>> loginWithEmail(@RequestBody Map<String, String> credentials) {
        try {
            String email = credentials.get("email");
            String code = credentials.get("code");
            
            if (email == null || email.trim().isEmpty()) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("邮箱不能为空"));
            }
            
            if (code == null || code.trim().isEmpty()) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("验证码不能为空"));
            }
            
            // 验证邮箱验证码
            if (!verificationCodeService.verifyEmailCode(email, code)) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("验证码错误或已过期"));
            }
            
            // 查找用户，如果不存在则自动注册
            User user = userService.findByEmail(email);
            if (user != null) {
                // 检查用户是否被封禁
                if (user.getIsActive() == null || !user.getIsActive()) {
                    return ResponseEntity.badRequest().body(createErrorResponse("您的账号已被封禁，请联系管理员"));
                }
            }
            if (user == null) {
                // 自动注册新用户
                try {
                    
                    // 从邮箱生成用户名（去掉@符号及后面的部分）
                    String emailPrefix = email.split("@")[0];
                    String emailDomain = email.contains("@") ? email.split("@")[1] : "";
                    
                    // 清理邮箱前缀（移除特殊字符，只保留字母、数字、下划线）
                    String cleanPrefix = emailPrefix.replaceAll("[^a-zA-Z0-9_]", "_");
                    
                    // 生成基础用户名：优先使用邮箱前缀
                    String baseUsername = cleanPrefix;
                    
                    // 确保用户名不为空且至少3个字符
                    if (baseUsername.length() < 3) {
                        baseUsername = baseUsername + "_" + System.currentTimeMillis() % 1000;
                    }
                    
                    // 确保用户名长度不超过50个字符
                    if (baseUsername.length() > 50) {
                        baseUsername = baseUsername.substring(0, 50);
                    }
                    
                    // 确保用户名唯一
                    // 策略：如果基础用户名已存在，添加邮箱域名的简短标识或数字后缀
                    String username = baseUsername;
                    int counter = 1;
                    int maxAttempts = 1000;
                    
                    while (userService.findByUsernameOrNull(username) != null && counter <= maxAttempts) {
                        // 尝试策略1：添加邮箱域名的简短标识（如 qq, 163）
                        if (counter == 1 && emailDomain.length() > 0) {
                            String domainShort = emailDomain.split("\\.")[0]; // 获取域名第一部分
                            if (domainShort.length() > 0 && domainShort.length() <= 5) {
                                String candidateUsername = baseUsername.length() > 45 ? 
                                    baseUsername.substring(0, 45) : baseUsername;
                                candidateUsername = candidateUsername + "_" + domainShort;
                                if (candidateUsername.length() <= 50 && 
                                    userService.findByUsernameOrNull(candidateUsername) == null) {
                                    username = candidateUsername;
                                    break;
                                }
                            }
                        }
                        
                        // 策略2：添加数字后缀
                        String baseForSuffix = baseUsername.length() > 45 ? 
                            baseUsername.substring(0, 45) : baseUsername;
                        String newUsername = baseForSuffix + counter;
                        if (newUsername.length() > 50) {
                            newUsername = newUsername.substring(0, 50);
                        }
                        username = newUsername;
                        counter++;
                    }
                    
                    // 如果还是冲突，使用时间戳确保唯一性
                    if (counter > maxAttempts || userService.findByUsernameOrNull(username) != null) {
                        username = "user_" + System.currentTimeMillis();
                        logger.warn("邮箱验证码登录 - 用户名冲突过多，使用时间戳生成: '{}'", username);
                    }
                    
                    // 直接创建用户对象并设置所有必要字段
                    user = new User();
                    
                    // 生成唯一用户ID（重试最多10次确保唯一性）
                    String generatedUserId = null;
                    for (int i = 0; i < 10; i++) {
                        generatedUserId = UserIdGenerator.generate();
                        if (!userService.existsByUserId(generatedUserId)) {
                            break;
                        }
                        logger.warn("邮箱验证码登录 - 用户ID冲突，重新生成");
                    }
                    user.setUserId(generatedUserId);
                    logger.info("邮箱验证码登录 - 生成用户ID: {}", generatedUserId);
                    
                    user.setUsername(username);
                    user.setEmail(email);
                    user.setPasswordHash(""); // 邮箱登录不需要密码
                    user.setRole("ROLE_USER"); // 默认为普通用户
                    user.setPoints(50); // 默认50积分
                    user.setFrozenPoints(0); // 默认冻结积分为0
                    user.setNickname(username); // 默认昵称为用户名
                    user.setIsActive(true);
                    
                    // 保存用户（@PrePersist 会自动设置 createdAt 等字段）
                    user = userService.save(user);
                    
                    // 为新用户创建默认会员记录（标准会员，到期时间为1年后）
                    createDefaultMembershipForUser(user);
                } catch (IllegalArgumentException e) {
                    logger.error("自动注册用户失败: {}", email, e);
                    return ResponseEntity.badRequest()
                        .body(createErrorResponse("用户注册失败：" + e.getMessage()));
                } catch (Exception e) {
                    logger.error("自动注册用户失败: {}", email, e);
                    return ResponseEntity.badRequest()
                        .body(createErrorResponse("用户注册失败：" + e.getMessage()));
                }
            }
            
            // 获取动态配置的过期时间（确保不为0或null，默认24小时）
            SystemSettings settings = systemSettingsService.getOrCreate();
            int expireHours = (settings.getTokenExpireHours() != null && settings.getTokenExpireHours() > 0) ? settings.getTokenExpireHours() : 24;
            long expireMs = expireHours * 60L * 60L * 1000L; // 转换为毫秒
            long expireSeconds = expireHours * 60L * 60L; // 转换为秒
            
            // 生成JWT Token
            String token = jwtUtils.generateToken(user.getUsername(), user.getRole(), user.getId(), expireMs);
            
            // 将 token 保存到 Redis
            redisTokenService.saveToken(user.getUsername(), token, expireSeconds);
            
            // 检查是否需要设置密码（首次登录的用户密码为空）
            boolean needsPasswordChange = user.getPasswordHash() == null || user.getPasswordHash().isEmpty();
            
            Map<String, Object> body = new HashMap<>();
            body.put("success", true);
            body.put("message", "登录成功");
            
            Map<String, Object> data = new HashMap<>();
            data.put("user", user);
            data.put("token", token);
            data.put("needsPasswordChange", needsPasswordChange); // 告诉前端是否需要修改密码
            body.put("data", data);
            
            return ResponseEntity.ok(body);
            
        } catch (Exception e) {
            logger.error("邮箱验证码登录失败：", e);
            return ResponseEntity.badRequest()
                .body(createErrorResponse("登录失败：" + e.getMessage()));
        }
    }
    
    
    /**
     * 用户注册
     */
    @PostMapping("/register")
    public ResponseEntity<Map<String, Object>> register(@RequestBody Map<String, String> requestData) {
        try {
            String username = requestData.get("username");
            String email = requestData.get("email");
            String password = requestData.get("password");
            
            // 验证必填字段
            if (username == null || username.trim().isEmpty()) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("用户名不能为空"));
            }
            
            if (email == null || email.trim().isEmpty()) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("邮箱不能为空"));
            }
            
            if (password == null || password.trim().isEmpty()) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("密码不能为空"));
            }
            
            // 检查用户名是否已存在
            User existingUser = userService.findByUsernameOrNull(username);
            if (existingUser != null) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("用户名已存在"));
            }
            
            // 检查邮箱是否已存在
            User existingEmail = userService.findByEmailOrNull(email);
            if (existingEmail != null) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("邮箱已存在"));
            }
            
            // 使用 register 方法创建用户（会自动编码密码）
            User savedUser = userService.register(username, email, password);
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "注册成功");
            // 不返回密码哈希
            savedUser.setPasswordHash(null);
            response.put("data", savedUser);
            
            return ResponseEntity.ok(response);
            
        } catch (IllegalArgumentException e) {
            logger.warn("注册失败：{}", e.getMessage());
            return ResponseEntity.badRequest()
                .body(createErrorResponse(e.getMessage()));
        } catch (Exception e) {
            logger.error("注册失败：", e);
            return ResponseEntity.badRequest()
                .body(createErrorResponse("注册失败：" + e.getMessage()));
        }
    }
    
    /**
     * 用户登出
     */
    @PostMapping("/logout")
    public ResponseEntity<Map<String, Object>> logout(Authentication authentication, HttpServletRequest request) {
        try {
            String username = null;
            String token = null;
            
            // 从请求头获取 token
            String authHeader = request.getHeader("Authorization");
            if (authHeader != null && authHeader.startsWith("Bearer ")) {
                token = authHeader.substring(7);
                // 从 token 中获取用户名
                try {
                    username = jwtUtils.getUsernameFromToken(token);
                } catch (Exception e) {
                    logger.warn("从 token 获取用户名失败: {}", e.getMessage());
                }
            }
            
            // 如果从 token 获取失败，尝试从 Authentication 获取
            if (username == null && authentication != null && authentication.isAuthenticated()) {
                username = authentication.getName();
            }
            
            // 从 Redis 删除 token
            if (username != null && token != null) {
                redisTokenService.removeToken(username, token);
                logger.info("用户登出成功，token 已从 Redis 删除: username={}", username);
            }
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "登出成功");
            
            return ResponseEntity.ok(response);
        } catch (Exception e) {
            logger.error("登出失败：", e);
            Map<String, Object> response = new HashMap<>();
            response.put("success", true); // 即使出错也返回成功，因为客户端无论如何都会清除本地 token
            response.put("message", "登出成功");
            return ResponseEntity.ok(response);
        }
    }
    
    /**
     * 强制登出所有设备
     * 删除用户在 Redis 中的所有 token
     */
    @PostMapping("/logout/all")
    public ResponseEntity<Map<String, Object>> logoutAll(Authentication authentication) {
        try {
            if (authentication != null && authentication.isAuthenticated()) {
                String username = authentication.getName();
                redisTokenService.removeAllTokens(username);
                logger.info("用户所有设备登出成功: username={}", username);
                
                Map<String, Object> response = new HashMap<>();
                response.put("success", true);
                response.put("message", "所有设备已登出");
                return ResponseEntity.ok(response);
            }
            
            return ResponseEntity.badRequest().body(createErrorResponse("用户未登录"));
        } catch (Exception e) {
            logger.error("强制登出所有设备失败：", e);
            return ResponseEntity.badRequest().body(createErrorResponse("登出失败：" + e.getMessage()));
        }
    }
    
    /**
     * 获取当前用户信息
     */
    @GetMapping("/me")
    public ResponseEntity<Map<String, Object>> getCurrentUser(Authentication authentication, 
                                                               jakarta.servlet.http.HttpServletRequest request) {
        try {
            if (authentication != null && authentication.isAuthenticated()) {
                User user = null;
                String username = authentication.getName();
                
                try {
                    // 首先尝试通过用户名查找
                    user = userService.findByUsernameOrNull(username);

                    // 如果通过用户名找不到，尝试从JWT token中获取用户ID
                    if (user == null) {
                        String authHeader = request.getHeader("Authorization");
                        if (authHeader != null && authHeader.startsWith("Bearer ")) {
                            String token = authHeader.substring(7);
                            try {
                                Long userId = jwtUtils.getUserIdFromToken(token);
                                if (userId != null) {
                                    logger.warn("通过用户名未找到用户，尝试通过用户ID查找: {}", userId);
                                    user = userService.findById(userId);
                                }
                            } catch (Exception e) {
                                logger.warn("从token获取用户ID失败: {}", e.getMessage());
                            }
                        }
                    }

                    // 如果通过用户名找不到，尝试通过邮箱查找（兼容邮箱登录的情况）
                    if (user == null && username.contains("@")) {
                        logger.warn("通过用户名未找到用户，尝试通过邮箱查找: {}", username);
                        user = userService.findByEmailOrNull(username);
                    }
                    
                    if (user == null) {
                        logger.error("无法找到用户，用户名/邮箱: {}", username);
                        return ResponseEntity.badRequest()
                            .body(createErrorResponse("用户不存在: " + username));
                    }
                    
                    Map<String, Object> response = new HashMap<>();
                    response.put("success", true);
                    response.put("data", user);
                    return ResponseEntity.ok(response);
                } catch (Exception e) {
                    logger.error("查找用户失败: {}", username, e);
                    return ResponseEntity.badRequest()
                        .body(createErrorResponse("查找用户失败: " + e.getMessage()));
                }
            }
            
            return ResponseEntity.badRequest()
                .body(createErrorResponse("用户未登录"));
            
        } catch (Exception e) {
            logger.error("获取用户信息失败：", e);
            return ResponseEntity.badRequest()
                .body(createErrorResponse("获取用户信息失败: " + e.getMessage()));
        }
    }

    /**
     * 修改当前登录用户密码
     * 支持首次设置密码（isFirstTimeSetup=true时不验证旧密码）
     */
    @PostMapping("/change-password")
    public ResponseEntity<Map<String, Object>> changePassword(@RequestBody Map<String, Object> requestBody,
                                                              Authentication authentication,
                                                              HttpServletRequest request) {
        try {
            String oldPassword = (String) requestBody.get("oldPassword");
            String newPassword = (String) requestBody.get("newPassword");
            Boolean isFirstTimeSetup = Boolean.TRUE.equals(requestBody.get("isFirstTimeSetup"));

            // 尝试从 Spring Security 上下文中获取当前用户名
            User user = null;
            if (authentication != null && authentication.isAuthenticated()) {
                String username = authentication.getName();
                user = userService.findByUsernameOrNull(username);
            }

            // 如果通过用户名未找到，再从JWT中解析用户ID
            if (user == null) {
                String authHeader = request.getHeader("Authorization");
                String token = jwtUtils.extractTokenFromHeader(authHeader);
                if (token != null) {
                    Long userId = jwtUtils.getUserIdFromToken(token);
                    if (userId != null) {
                        user = userService.findById(userId);
                    }
                }
            }

            if (user == null) {
                return ResponseEntity.badRequest()
                    .body(createErrorResponse("用户未登录或会话已失效"));
            }

            // changePassword 方法内部已处理首次设置密码场景
            // 如果用户没有密码，可以直接设置新密码，不需要验证旧密码
            userService.changePassword(user.getId(), isFirstTimeSetup ? null : oldPassword, newPassword);

            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("message", "密码修改成功");
            return ResponseEntity.ok(response);

        } catch (IllegalArgumentException ex) {
            return ResponseEntity.badRequest()
                .body(createErrorResponse(ex.getMessage()));
        } catch (Exception e) {
            logger.error("修改密码失败：", e);
            return ResponseEntity.badRequest()
                .body(createErrorResponse("修改密码失败：" + e.getMessage()));
        }
    }
    
    /**
     * 检查用户名是否存在
     */
    @GetMapping("/public/users/exists/username")
    public ResponseEntity<Map<String, Object>> checkUsernameExists(@RequestParam String value) {
        try {
            boolean exists = userService.findByUsername(value) != null;
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", Map.of("exists", exists));
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("检查用户名失败：", e);
            return ResponseEntity.badRequest()
                .body(createErrorResponse("检查用户名失败"));
        }
    }
    
    /**
     * 检查邮箱是否存在
     */
    @GetMapping("/public/users/exists/email")
    public ResponseEntity<Map<String, Object>> checkEmailExists(@RequestParam String value) {
        try {
            boolean exists = userService.findByEmail(value) != null;
            
            Map<String, Object> response = new HashMap<>();
            response.put("success", true);
            response.put("data", Map.of("exists", exists));
            
            return ResponseEntity.ok(response);
            
        } catch (Exception e) {
            logger.error("检查邮箱失败：", e);
            return ResponseEntity.badRequest()
                .body(createErrorResponse("检查邮箱失败"));
        }
    }
    
    /**
     * 为新用户创建默认会员记录（免费会员，永久有效）
     */
    private void createDefaultMembershipForUser(User user) {
        try {
            // 查找免费会员等级（新用户注册默认）
            Optional<MembershipLevel> freeLevel = membershipLevelRepository.findByName("free");
            if (freeLevel.isEmpty()) {
                logger.warn("未找到免费会员等级(free)，跳过创建会员记录");
                return;
            }
            
            UserMembership membership = new UserMembership();
            membership.setUserId(user.getId());
            membership.setMembershipLevelId(freeLevel.get().getId());
            membership.setStartDate(LocalDateTime.now());
            membership.setEndDate(LocalDateTime.of(2099, 12, 31, 23, 59, 59)); // 免费会员永久有效
            membership.setStatus("ACTIVE");
            membership.setAutoRenew(false);
            membership.setCreatedAt(LocalDateTime.now());
            
            userMembershipRepository.save(membership);
            logger.info("✅ 为新用户创建默认会员记录: userId={}, level=免费会员(永久有效)", user.getId());
        } catch (Exception e) {
            logger.error("创建默认会员记录失败: userId={}", user.getId(), e);
            // 不抛出异常，允许用户注册成功
        }
    }
    
    private Map<String, Object> createErrorResponse(String message) {
        Map<String, Object> response = new HashMap<>();
        response.put("success", false);
        response.put("message", message);
        return response;
    }
}
