package com.stdproject.controller;

import com.stdproject.common.Constants;
import com.stdproject.common.OperationLog;
import com.stdproject.common.Result;
import com.stdproject.entity.AppUser;
import com.stdproject.service.IAppUserService;
import com.stdproject.utils.CaptchaUtils;
import com.stdproject.utils.JwtUtils;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 认证控制器
 *
 * @author StdProject
 */
@Tag(name = "认证管理", description = "用户登录、登出、验证码等认证相关接口")
@RestController
@RequestMapping("/auth")
@Slf4j
public class AuthController {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private CaptchaUtils captchaUtils;

    @Autowired
    private IAppUserService appUserService;



    /**
     * 登录请求类
     */
    public static class LoginRequest {
        @NotBlank(message = "用户名不能为空")
        private String username;

        @NotBlank(message = "密码不能为空")
        private String password;

        @NotBlank(message = "验证码不能为空")
        private String captcha;

        @NotBlank(message = "验证码Key不能为空")
        private String captchaKey;

        // Getters and Setters
        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
        public String getCaptcha() { return captcha; }
        public void setCaptcha(String captcha) { this.captcha = captcha; }
        public String getCaptchaKey() { return captchaKey; }
        public void setCaptchaKey(String captchaKey) { this.captchaKey = captchaKey; }
    }

    /**
     * 修改密码请求类
     */
    public static class ChangePasswordRequest {
        @NotBlank(message = "原密码不能为空")
        private String oldPassword;

        @NotBlank(message = "新密码不能为空")
        private String newPassword;

        // Getters and Setters
        public String getOldPassword() { return oldPassword; }
        public void setOldPassword(String oldPassword) { this.oldPassword = oldPassword; }
        public String getNewPassword() { return newPassword; }
        public void setNewPassword(String newPassword) { this.newPassword = newPassword; }
    }

    /**
     * 生成验证码
     */
    @Operation(summary = "生成验证码", description = "生成图形验证码")
    @GetMapping("/captcha")
    public Result<Map<String, String>> generateCaptcha() {
        try {
            // 生成验证码
            CaptchaUtils.CaptchaResult captchaResult = captchaUtils.generateCaptcha();

            // 生成验证码Key
            String captchaKey = UUID.randomUUID().toString();

            // 注意：验证码应当存储在会话中或其他存储中，此处省略存储步骤
            // 在实际应用中，可以使用Session或其他方式存储验证码

            Map<String, String> result = new HashMap<>();
            result.put("captchaKey", captchaKey);
            result.put("captchaImage", captchaResult.getImageBase64());
            result.put("code", captchaResult.getCode()); // 临时方案：直接返回验证码（生产环境不建议）

            return Result.success(result);
        } catch (Exception e) {
            log.error("生成验证码失败: {}", e.getMessage(), e);
            return Result.error("生成验证码失败");
        }
    }

    /**
     * 用户登录
     */
    @Operation(summary = "用户登录", description = "用户登录认证")
    @PostMapping("/login")
    @OperationLog(type = Constants.OPT_TYPE_LOGIN, module = "认证管理", description = "用户登录")
    public Result<Map<String, Object>> login(@Valid @RequestBody LoginRequest loginRequest, HttpServletRequest request) {
        try {
            // 注意：在实际应用中，应该从会话或其他存储中获取验证码进行验证
            // 此处简化处理，假设验证码已通过（实际应用中需要实现验证逻辑）
            // 如果使用了临时方案，可以从前端传回验证码进行比对

            // 进行身份认证
            Authentication authentication = authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(
                    loginRequest.getUsername(),
                    loginRequest.getPassword()
                )
            );
            AppUser user=appUserService.findByUsername(loginRequest.getUsername());
            // 设置认证信息到安全上下文
            SecurityContextHolder.getContext().setAuthentication(authentication);

            // 生成JWT Token
            String token = jwtUtils.generateToken(user.getUsername(),user.getId());

            Map<String, Object> result = new HashMap<>();
            result.put("token", token);
            result.put("userInfo", user);

            return Result.success(result);

        } catch (Exception e) {
            log.error("用户登录失败: {}", e.getMessage(), e);
            return Result.error("登录失败: " + e.getMessage());
        }
    }

    /**
     * 用户登出
     */
    @Operation(summary = "用户登出", description = "用户登出")
    @PostMapping("/logout")
    @OperationLog(type = Constants.OPT_TYPE_OTHER, module = "认证管理", description = "用户登出")
    public Result<Void> logout(HttpServletRequest request) {
        try {
            // 获取Token
            String token = request.getHeader(Constants.JWT_HEADER);
            if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
                token = token.substring(Constants.JWT_PREFIX.length());

                // 注意：在实际应用中，应该实现Token失效机制
                // 可以考虑使用短期Token或其他方式实现Token失效
                // 此处省略Token黑名单实现
            }

            // 清除安全上下文
            SecurityContextHolder.clearContext();

            return Result.success();
        } catch (Exception e) {
            log.error("用户登出失败: {}", e.getMessage(), e);
            return Result.error("登出失败");
        }
    }

    /**
     * 获取当前用户信息
     */
    @Operation(summary = "获取当前用户信息", description = "获取当前登录用户的详细信息")
    @GetMapping("/userinfo")
    public Result<AppUser> getCurrentUserInfo(HttpServletRequest request) {
        try {
            String token = request.getHeader(Constants.JWT_HEADER);
            if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
                token = token.substring(Constants.JWT_PREFIX.length());
                String username = jwtUtils.getUsernameFromToken(token);
                AppUser userInfo = appUserService.findByUsername(username);
                return Result.success(userInfo);
            }

            return Result.unauthorized();
        } catch (Exception e) {
            log.error("获取用户信息失败: {}", e.getMessage(), e);
            return Result.error("获取用户信息失败");
        }
    }

    /**
     * 修改密码
     */
    @Operation(summary = "修改密码", description = "修改当前用户密码")
    @PostMapping("/changePassword")
    @OperationLog(type = Constants.OPT_TYPE_UPDATE, module = "认证管理", description = "修改密码")
    public Result<Void> changePassword(@Valid @RequestBody ChangePasswordRequest request, HttpServletRequest httpRequest) {
        try {
            String token = httpRequest.getHeader(Constants.JWT_HEADER);
            if (token != null && token.startsWith(Constants.JWT_PREFIX)) {
                token = token.substring(Constants.JWT_PREFIX.length());
                String username = jwtUtils.getUsernameFromToken(token);

                boolean success = appUserService.changePassword(username, request.getOldPassword(), request.getNewPassword());
                if (success) {
                    return Result.success();
                } else {
                    return Result.error("原密码错误");
                }
            }

            return Result.unauthorized();
        } catch (Exception e) {
            log.error("修改密码失败: {}", e.getMessage(), e);
            return Result.error("修改密码失败");
        }
    }

    @PostMapping("/refreshToken")
    public Result<String> refreshToken(@RequestBody Map<String, String> params) {
        String refreshToken = params.get("refreshToken");

        if (refreshToken == null || refreshToken.trim().isEmpty()) {
            return Result.error("刷新令牌不能为空");
        }

        try {
            String username = jwtUtils.getUsernameFromToken(refreshToken);

            if (username != null && jwtUtils.validateToken(refreshToken, username)) {
                AppUser user = appUserService.findByUsername(username);
                String newAccessToken = jwtUtils.generateRefreshToken(user.getUsername(), user.getId());
                return Result.success(newAccessToken);
            } else {
                return Result.error("刷新令牌已失效");
            }
        } catch (Exception e) {
            log.error("刷新 Token 失败: {}", e.getMessage());
            return Result.error("刷新 Token 失败");
        }
    }


}
