package modules.user;

import com.alibaba.fastjson.JSONObject;
import com.jdcloud.sdk.service.sms.model.BatchSendResponse;
import com.jfinal.aop.Before;
import com.jfinal.aop.Inject;
import com.jfinal.kit.HashKit;
import com.jfinal.kit.StrKit;
import common.interceptor.LoginInterceptor;
import common.interceptor.empty.EmptyInterface;
import common.interceptor.role.RequiredRoleInterface;
import common.jfinal.AppConfig;
import common.model.User;
import common.utils.http.MyController;
import common.utils.http.MyRet;
import common.utils.http.VerifyCode;
import common.utils.hyg.AESUtils;
import common.utils.jdcloud.SMS;
import modules.order.OrderService;

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

public class UserController extends MyController {
    // 验证码相关的常量
    private static final long SEND_VERIFY_CODE_DELAY = 60 * 1000;               // 验证码发送间隔
    private static final long VERIFY_CODE_EXPIRATION_TIME = 5 * 60 * 1000;      // 验证码有效期，5 分钟 (300 秒)
    
    // 角色相关常量
    public static final int ROLE_SUPER_ADMIN = 0;                               // 超级管理员
    public static final int ROLE_CHECK_ADMIN = 1;                               // 审核管理员
    public static final int ROLE_USER = 2;                                      // 普通用户

    // 常量定义，避免魔法数字
    private static final int MAX_RETRY_TIMES = 5;
    private static final long RETRY_INTERVAL_MS = 100; // 重试间隔，可以根据需要调整
    
    @Inject
    private UserService service;
    
    @Inject
    private BalanceLogService depositLogService;

    @Inject
    private OrderService orderService;

    public void hello() {
        renderJson(MyRet.ok(service.hello()));
    }
    
    @EmptyInterface({"mobile_number"})
    public void sendVerifyCode() {
        // --- 核心修改部分 ---
        // 通过 MyController 获取解析后的 JSON 对象，拦截器也使用了这个方法
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);

        // 从 JSON 对象中获取 mobile_number
        String mobileNumber = requestBodyJson.getString("mobile_number");

        // 2. 校验发送间隔
        // 从 Session 中获取上次发送验证码的时间戳
        Long lastSendTime = getSessionAttr("last_send_verify_code_time");

        if (lastSendTime != null) {
            long currentTime = System.currentTimeMillis();
            if (currentTime - lastSendTime < SEND_VERIFY_CODE_DELAY) {
                // 计算还需要等待多少秒
                long remainingSeconds = (SEND_VERIFY_CODE_DELAY - (currentTime - lastSendTime)) / 1000 + 1; // +1 确保显示完整秒数
                renderJson(MyRet.fail("验证码发送过于频繁，请 " + remainingSeconds + " 秒后再试"));
                return;
            }
        }

        // 3. 生成验证码
        String verifyCode = VerifyCode.randomVerifyCode();
        
        // 4. 实际发送验证码
        try {
            // 调用带有重试机制的发送方法
            BatchSendResponse response = sendVerifyCodeWithRetry(mobileNumber, verifyCode, 1); // 初始重试次数为1
            String jsonResponse = JSONObject.toJSONString(response); // 或者使用 JsonKit.toJson(response);

            boolean isSentSuccessfully = response.getResult().getStatus();

            if (isSentSuccessfully) {
                // 5. 将验证码和发送时间戳存入 Session
                setSessionAttr("verify_mobile_number", mobileNumber); // 是谁发的验证码
                setSessionAttr("verify_code", verifyCode); // 验证码本身
                setSessionAttr("last_send_verify_code_time", System.currentTimeMillis()); // 记录本次发送时间戳

                renderJson(MyRet.ok("验证码已发送，请注意查收。").setData(jsonResponse));
            } else {
                // 短信服务商返回发送失败的情况处理
                AppConfig.LOGGER.error("发送验证码到 {} 失败，服务商返回失败状态。Response: {}", mobileNumber, jsonResponse);
                renderJson(MyRet.fail("验证码发送失败，请稍后再试").setData(jsonResponse));
            }
        } catch (Exception e) {
            // 达到最大重试次数后仍然失败
            AppConfig.LOGGER.error("发送验证码到 {} 最终失败，已重试 {} 次。异常信息: {}", mobileNumber, MAX_RETRY_TIMES, e.getMessage(), e);
            renderJson(MyRet.fail("验证码发送失败，请重试: " + e.getMessage()));
        }
    }

    @EmptyInterface({"mobile_number", "pwd_md5", "repeat_pwd_md5", "verify_code"})
    public void register() {
        // --- 核心修改部分：从 JSON 请求体中获取参数 ---
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);

        // 因为 EmptyInterceptor 已经保证了这些字段不为空，这里可以直接获取
        String mobileNumber = requestBodyJson.getString("mobile_number");
        String pwd = requestBodyJson.getString("pwd_md5");
        String repeatPwd = requestBodyJson.getString("repeat_pwd_md5");
        String userVerifyCode = requestBodyJson.getString("verify_code");

        // 2. 密码重复校验
        if (!pwd.equals(repeatPwd)) {
            renderJson(MyRet.fail("两次输入密码不一致"));
            return;
        }

        // 3. 验证码校验
        MyRet verifyCodeRet = checkVerifyCode(userVerifyCode, mobileNumber);
        if (!verifyCodeRet.isOk()) {
            renderJson(verifyCodeRet);
            return;
        }

        // 4. 构建 User 对象并处理业务逻辑
        // 因为 getPara("mobile_number") 已经获取了手机号，这里可以手动设置
        // 或者优化 getModel 的用法，让它只获取数据库字段，然后手动设置 mobileNumber。
        // 但为了保持原先 getModel 的语义，这里继续使用。
        User user = getModel(User.class, "", true);

        // 确保 mobile_number 填充正确
        if (StrKit.isBlank(user.getStr("mobile_number"))) {
            // 如果 getModel 没能获取到 mobile_number，则手动设置，确保数据完整性
            user.set("mobile_number", mobileNumber);
        }

        // 推荐人
        String referrerIdStr = requestBodyJson.getString("referrer_id");
        if (StrKit.notBlank(referrerIdStr)) {
            int referrerIdInt;
            try {
                referrerIdInt = Integer.parseInt(referrerIdStr);

                if (referrerIdInt <= 0) {
                    renderJson(MyRet.fail("推荐人(referrer_id)期待是正整数，你传的是: " + referrerIdStr));
                    return;
                }
                
                // 推荐人
                user.setReferrerId(referrerIdInt);
            } catch (Exception e) {
                renderJson(MyRet.fail("推荐人(referrer_id)格式不正确: " + e.getMessage()));
                return;
            }
        }

        // 参数补充
        user.setRole(2); // 2表示普通用户
        // 密码加密并存储
        user.setPwdMd5Md5(HashKit.md5(pwd));
        user.setIntegral(0);
        user.setIsDeleted(0);
        user.setIsEffective(0);
        user.setBalance((float) 0);

        // 5. 调用服务层进行用户保存
        renderJson(service.saveUser(user));
    }
    
    @Before(LoginInterceptor.class)
    @EmptyInterface({"pwd_md5", "repeat_pwd_md5", "verify_code"})
    public void updatePwd() {
        // --- 从 JSON 请求体中获取参数 ---
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
        String pwdMd5 = requestBodyJson.getString("pwd_md5");
        String repeatPwdMd5 = requestBodyJson.getString("repeat_pwd_md5");
        String verifyCode = requestBodyJson.getString("verify_code");

        // 获取当前已登录用户
        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));

        // 2. 密码重复校验
        if (!pwdMd5.equals(repeatPwdMd5)) {
            renderJson(MyRet.fail("两次输入密码不一致"));
            return;
        }

        // 3. 验证码校验
        MyRet verifyCodeRet = checkVerifyCode(verifyCode, getSessionAttr("mobile_number"));
        if (!verifyCodeRet.isOk()) {
            renderJson(verifyCodeRet);
            return;
        }

        user.set("pwd_md5_md5", HashKit.md5(pwdMd5));
        
        // 直接调用修改并返回
        if (user.update()) {
            renderJson(MyRet.ok("密码修改成功"));
        } else {
            renderJson(MyRet.fail("密码修改失败"));
        }
    }

    @EmptyInterface({"mobile_number"})
    public void login() {
        // --- 从 JSON 请求体中获取参数 ---
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);

        // 因为 EmptyInterceptor 已经保证了这些字段不为空，这里可以直接获取
        String mobileNumber = requestBodyJson.getString("mobile_number");
        String pwdMd5 = requestBodyJson.getString("pwd_md5");
        String verifyCode = requestBodyJson.getString("verify_code");

        // 1. 校验手机号是否被注册
        if (!service.isUserExists(mobileNumber)) {
            renderJson(MyRet.fail("该手机号未注册。"));
            return;
        }
        
        // 2.判断是使用密码还是验证码登录
        MyRet ret = MyRet.fail("参数缺失，需要pwd_md5或verify_code").setData(requestBodyJson);
        // 如果传入了密码优先使用密码登录
        if (StrKit.notBlank(pwdMd5)) {
            ret = service.login(mobileNumber, HashKit.md5(pwdMd5));
        } 
        // 如果有验证码传入进行验证码校验
        if (StrKit.notBlank(verifyCode)) {
            MyRet verifyCodeRet = checkVerifyCode(verifyCode, mobileNumber);
            if (!verifyCodeRet.isOk()) {
                renderJson(verifyCodeRet);
                return;
            }
            
            ret = service.verifyCodeLogin(mobileNumber);
        }
        
        if (ret.isOk()) {
            String token = createToken("dl-token");
            // 更新用户登录时间
            service.updateUserLoginTime(mobileNumber);
            // 更新用户token
            service.updateToken(mobileNumber, token);
            
            // 将token传回前端
            ret.set("token", token);

            // 其它参数的封装
            setSessionAttr("user_id", ((User)ret.get("data")).getStr("id"));
            setSessionAttr("mobile_number", ((User)ret.get("data")).getStr("mobile_number"));
            setSessionAttr("role", ((User)ret.get("data")).getStr("role"));
        }
        
        renderJson(ret);
    }
    
    @Before(LoginInterceptor.class)
    @EmptyInterface({"page_size", "page_number"})
    public void depositLogs() {
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);

        // 页面大小
        String pageSizeStr = requestBodyJson.getString("page_size");
        int pageSizeInt;
        try {
            pageSizeInt = Integer.parseInt(pageSizeStr);

            if (pageSizeInt <= 0) {
                renderJson(MyRet.fail("页面大小(page_size)期待是正整数，你传的是: " + pageSizeStr));
                return;
            }
        } catch (Exception e) {
            renderJson(MyRet.fail("页面大小(page_size)格式不正确: " + e.getMessage()));
            return;
        }

        // 页码
        String pageNumberStr = requestBodyJson.getString("page_number");
        int pageNumberInt;
        try {
            pageNumberInt = Integer.parseInt(pageNumberStr);

            if (pageNumberInt <= 0) {
                renderJson(MyRet.fail("页码(page_number)期待是正整数，你传的是: " + pageNumberStr));
                return;
            }
        } catch (Exception e) {
            renderJson(MyRet.fail("页码(page_number)格式不正确: " + e.getMessage()));
            return;
        }

        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));
        renderJson(depositLogService.findForUser(pageNumberInt, pageSizeInt, user.getId()));
    }
    
    // 慧用工免登请求地址，用来换取手机号
    public void tokenToMobileNumber() {
//        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
        
        String token = getPara("token");

        AppConfig.LOGGER.info("有免登请求: form-data:{}", getPara("token"));
        
        // 顶层 Map 用于封装整个 JSON 结构
        Map<String, Object> responseJson = new HashMap<>();
        // data Map 用于封装 workerMobile 等信息
        Map<String, String> data = new HashMap<>();

        if (StrKit.notBlank(token)) {
            String mobileNumber = service.findMobileNumberByToken(token);

            if (StrKit.notBlank(mobileNumber)) {
                // 成功获取手机号
                responseJson.put("statusCode", "000000");
                responseJson.put("statusText", "获取手机号成功");

                data.put("workerMobile", mobileNumber);
                data.put("workerName", ""); // 示例中为空，根据实际业务填充
                data.put("idCard", "");     // 示例中为空，根据实际业务填充

                responseJson.put("data", data);
            } else {
                responseJson.put("statusCode", "100001"); // 或 STATUS_CODE_TOKEN_EXPIRED
                responseJson.put("statusText", "token无效或已过期，未找到匹配的手机号");

                data.put("workerMobile", "");
                data.put("workerName", "");
                data.put("idCard", "");
                responseJson.put("data", data);
            }
            
            renderText(service.findMobileNumberByToken(token));
        } else {
            // token 为空
            responseJson.put("statusCode", "100001");
            responseJson.put("statusText", "token不能为空");

            data.put("workerMobile", "");
            data.put("workerName", "");
            data.put("idCard", "");
            responseJson.put("data", data);
        }

        renderJson(responseJson);
    }

    // 慧用工签约回调地址
    public void hygSign() {
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
        String businessBodyEncryptedHex = requestBodyJson.getString("businessBody");

        AppConfig.LOGGER.info("签约回调: json:{}", requestBodyJson.toJSONString());

        try {
            String body = AESUtils.decryptByHex(businessBodyEncryptedHex);
            JSONObject businessBody = JSONObject.parseObject(body);
            
            String workerId = businessBody.getString("workerId");
            String agreeState = businessBody.getString("agreeState");
            String workerMobile = businessBody.getString("workerMobile");
            User user = service.findUserByMobileNumber(workerMobile);
            
            // 签约成功，则赋予用户workerId
            if (agreeState.equals("2")) {
                user.setHygWorkerId(workerId);
            }
            // 无论成功与否，签约结果都放到数据库，方便维护
            user.setHygSignRst(businessBody.toJSONString());
            // 对user进行升级
            user.update();

            AppConfig.LOGGER.info(businessBody.toJSONString());

            Map<String, Object> responseJson = new HashMap<>();
            responseJson.put("statusCode", "000000");
            responseJson.put("statusText", "回调成功");

            renderJson(responseJson);
        } catch (Exception e) {
            Map<String, Object> responseJson = new HashMap<>();
            responseJson.put("statusCode", "100000");
            responseJson.put("statusText", "回调失败 " + e.getMessage());

            AppConfig.LOGGER.info("回调失败 " + e.getMessage());

            renderJson(responseJson);
        }
    }

    @Before(LoginInterceptor.class)
    public void getBalance() {
        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));

        if (user == null) {
            removeSessionAttr("dl-token");
            removeSessionAttr("role");
            removeSessionAttr("mobile_number");

            renderJson(MyRet.fail("登录信息失效，请重新登录。").setCode(MyRet.CODE_NO_LOGIN));
        } else {
            setSessionAttr("role", user.getRole().toString());

            renderJson(MyRet.ok("获取成功").setData(user.getBalance()));
        }
    }

    @Before(LoginInterceptor.class)
    public void team() {
        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));
        
        renderJson(service.team(user.getId()));
    }

    @Before(LoginInterceptor.class)
    public void getUserInfo() {
        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));

        if (user == null) {
            removeSessionAttr("dl-token");
            removeSessionAttr("role");
            removeSessionAttr("mobile_number");
            
            renderJson(MyRet.fail("登录信息失效，请重新登录。").setCode(MyRet.CODE_NO_LOGIN));
        } else {
            setSessionAttr("role", user.getRole().toString());
            
            service.flushHygWorkerDetails(user);
            
            renderJson(MyRet.ok("获取成功").setData(user));
        }
    }
    
    @Before(LoginInterceptor.class)
    public void nftList() {
        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));
        
        renderJson(orderService.findNftListByUser(user.getId()));
    }
    
    @Before(LoginInterceptor.class)
    public void getBankInfo() {
        // 先判断实名认证过没过
        User user = service.findUserByMobileNumber(getSessionAttr("mobile_number"));
        if (StrKit.isBlank(user.getHygWorkerId())) {
            renderJson(MyRet.fail("请先进行实名认证").setCode(MyRet.CODE_NO_AUTH));
            return;
        }
        
        // 用户银行卡号
        String userBackCard = user.getHygBankCard();
        renderJson(MyRet.ok("请核对提现银行卡号，提现第三方平台会收取7.5%的手续费！").setData(userBackCard));
    }

    public void logout() {
        removeSessionAttr("user_id");
        removeSessionAttr("mobile_number");
        removeSessionAttr("dl-token");
        removeSessionAttr("role");

        renderJson(MyRet.ok("已成功登出。"));
    }

    @Before(LoginInterceptor.class)
    @RequiredRoleInterface({UserController.ROLE_SUPER_ADMIN})
    public void teamInfoByAdmin() {
        renderJson(service.teamInfoByAdmin());
    }

    /**
     * 更新用户的方法，传什么更新什么，不传就不更新，id必须传
     */
    @Before(LoginInterceptor.class)
    @RequiredRoleInterface({UserController.ROLE_SUPER_ADMIN})
    @EmptyInterface({"id"})
    public void updateByAdmin() {
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
        String id = requestBodyJson.getString("id");
        
        User user = service.findUserById(id);

        // 检查用户合法性
        if (user == null) {
            renderJson(MyRet.fail("用户获取不合法，该id对应的用户不存在，不要乱传参数。id: " + id));
            return;
        }
        
        // 校验昵称是否需要修改
        String nickname = requestBodyJson.getString("nickname");
        if (StrKit.notBlank(nickname)) {
            user.set("nickname", nickname);
        }
        
        // 校验手机号是否需要修改
        String mobileNumber = requestBodyJson.getString("mobile_number");
        if (StrKit.notBlank(mobileNumber)) {
            user.set("mobile_number", mobileNumber);
        }
        
        // 密码修改
        String pwdMd5 = requestBodyJson.getString("pwd_md5");
        if (StrKit.notBlank(pwdMd5)) {
            user.set("pwd_md5_md5", HashKit.md5(pwdMd5));
        }

        // 权限修改
        String roleStr = requestBodyJson.getString("role");
        if (StrKit.notBlank(roleStr)) {
            try {
                int roleInt = Integer.parseInt(roleStr); // 转换为 int 类型
                
                if (roleInt == ROLE_SUPER_ADMIN) {
                    renderJson(MyRet.fail("为了安全考虑！不能在该接口设置超级管理员！请联系开发者处理！"));
                    return;
                } else if (user.getInt("role") == 0) {
                    renderJson(MyRet.fail("为了安全考虑！不能在该接口将超级管理员降级！请联系开发者处理！"));
                    return;
                } else {
                    user.set("role", roleInt);
                }
            } catch (Exception e) {
                // 处理转换失败的情况，例如记录日志，或者返回错误信息给前端
                renderJson(MyRet.fail("role 格式不正确" + e.getMessage()));
                return; // 中断后续操作
            }
        }

        // 推荐人修改
        String referrerIdStr = requestBodyJson.getString("referrer_id");
        if (StrKit.notBlank(referrerIdStr)) {
            try {
                long referrerIdLong = Long.parseLong(referrerIdStr); // 或者 int，根据数据库字段大小
                user.set("referrer_id", referrerIdLong);
            } catch (Exception e) {
                renderJson(MyRet.fail("referrer_id 格式不正确: " + e.getMessage()));
                return;
            }
        }

        // 积分修改
        String integralStr = requestBodyJson.getString("integral");
        if (StrKit.notBlank(integralStr)) {
            try {
                int integralInt = Integer.parseInt(integralStr);
                user.set("integral", integralInt);
            } catch (Exception e) {
                renderJson(MyRet.fail("integral 格式不正确: " + e.getMessage()));
                return;
            }
        }
        
        // 更新时间
        user.set("update_time", System.currentTimeMillis());
        
        // 执行更新业务
        if (user.update()) {
            renderJson(MyRet.ok("用户更新成功").setData(service.findUserByMobileNumber(user.getMobileNumber())));
        } else {
            renderJson(MyRet.fail("用户更新失败，请将此日志复制给开发者" + user));
        }
    }

    @Before(LoginInterceptor.class)
    @RequiredRoleInterface({UserController.ROLE_SUPER_ADMIN})
    public void count() {
        renderJson(MyRet.ok("查询成功").setData(service.count(null)));
    }

    @Before(LoginInterceptor.class)
    @RequiredRoleInterface({UserController.ROLE_SUPER_ADMIN})
    @EmptyInterface({"page_size", "page_number"})
    public void users() {
        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
        
        // 页面大小
        String pageSizeStr = requestBodyJson.getString("page_size");
        int pageSizeInt;
        try {
            pageSizeInt = Integer.parseInt(pageSizeStr);

            if (pageSizeInt <= 0) {
                renderJson(MyRet.fail("页面大小(page_size)期待是正整数，你传的是: " + pageSizeStr));
                return;
            }
        } catch (Exception e) {
            renderJson(MyRet.fail("页面大小(page_size)格式不正确: " + e.getMessage()));
            return;
        }

        // 页码
        String pageNumberStr = requestBodyJson.getString("page_number");
        int pageNumberInt;
        try {
            pageNumberInt = Integer.parseInt(pageNumberStr);
            
            if (pageNumberInt <= 0) {
                renderJson(MyRet.fail("页码(page_number)期待是正整数，你传的是: " + pageNumberStr));
                return;
            }
        } catch (Exception e) {
            renderJson(MyRet.fail("页码(page_number)格式不正确: " + e.getMessage()));
            return;
        }

        // 查询条件
        String keywords = requestBodyJson.getString("keywords");
        
        // 最终结果封装
        List<User> users = service.users(pageNumberInt, pageSizeInt, keywords);
        Integer totalUsers = service.count(keywords);

        Map<String, Object> response = new HashMap<>();
        response.put("list", users);
        response.put("total_row", users.toArray().length);
        response.put("total_page", 1 + (users.toArray().length / pageSizeInt));
        response.put("page_size", pageSizeInt);
        response.put("page_number", pageNumberInt);
        response.put("total_user_count", totalUsers);
        
        renderJson(MyRet.ok("查询成功").setData(response));
    }
    
    /*
    * 
    ### 验证码修改密码
    POST {{ baseUrl }}/user/updatePwd
    Content-Type: application/json
    
    {
      "mobile_number": "17781855864",
      "new_pwd_md5": "e10adc3949ba59abbe56e057f20f883e",
      "verify_code": "9119"
    }
    * 
    * */

    /**
     * 私有辅助方法：发送验证码并进行重试
     *
     * @param mobileNumber 手机号码
     * @param verifyCode 验证码
     * @param retryCount 当前重试次数 (1到MAX_RETRY_TIMES)
     * @return BatchSendResponse 短信发送结果
     * @throws Exception 如果达到最大重试次数后仍然失败
     */
    private BatchSendResponse sendVerifyCodeWithRetry(String mobileNumber, String verifyCode, int retryCount) throws Exception {
        try {
            AppConfig.LOGGER.info("尝试发送验证码到 {} (第 {} 次尝试)", mobileNumber, retryCount);
            BatchSendResponse response = SMS.sendVerifyCodeByMobileNumber(mobileNumber, verifyCode);

            // 检查短信服务商返回的状态，如果认为虽然没抛异常但实际失败了，也可以在这里触发重试
            // 例如：response.errorCode != 0
            if (!response.getResult().getStatus()) {
                // 如果服务商明确返回失败（比如手机号不合法等业务错误，并不是网络异常）
                // 此时不应该重试，直接抛出异常，让上层处理
                AppConfig.LOGGER.warn("短信服务商返回失败状态，不进行重试。Mobile: {}, Code: {}, Response: {}", mobileNumber, verifyCode, JSONObject.toJSONString(response));
                throw new RuntimeException("短信服务商返回失败码，请检查手机号或稍后再试。");
            }
            return response; // 成功发送，直接返回
        } catch (Exception e) {
            AppConfig.LOGGER.warn("发送验证码到 {} 失败 (第 {} 次尝试)，准备重试。异常信息: {}", mobileNumber, retryCount, e.getMessage());

            if (retryCount < MAX_RETRY_TIMES) {
                // 短暂等待再重试，避免立即再次请求导致服务崩溃
                try {
                    Thread.sleep(RETRY_INTERVAL_MS * retryCount); // 逐渐增加重试间隔
                } catch (InterruptedException ie) {
                    Thread.currentThread().interrupt(); // 恢复中断状态
                    AppConfig.LOGGER.error("重试等待被中断，立即进行下次重试或抛出异常。");
                    // 这里可以选择不立即重试，直接抛出异常，或继续进行下次重试
                }
                return sendVerifyCodeWithRetry(mobileNumber, verifyCode, retryCount + 1); // 递归重试
            } else {
                AppConfig.LOGGER.error("发送验证码到 {} 失败，已达最大重试次数 {}。", mobileNumber, MAX_RETRY_TIMES, e);
                throw e; // 抛出异常，让调用者捕获并处理
            }
        }
    }
    
    //    @EmptyInterface(keyArray = {"mobile_number", "new_pwd_md5", "verify_code"})
    //    public void updatePwd() {
    //        // --- 核心修改部分：从 JSON 请求体中获取参数 ---
    //        JSONObject requestBodyJson = MyController.getJsonModelByRequestAndType(getRequest(), JSONObject.class);
    //
    //        // 因为 EmptyInterceptor 已经保证了这些字段不为空，这里可以直接获取
    //        String mobileNumber = requestBodyJson.getString("mobile_number");
    //        String pwdMd5 = requestBodyJson.getString("new_pwd_md5");
    //        String verifyCode = requestBodyJson.getString("verify_code");
    //    }
    
    private MyRet checkVerifyCode(String userVerifyCode, String mobileNumber) {
        // 3. 验证码校验
        String storedVerifyCode = getSessionAttr("verify_code");
        Long sendTime = getSessionAttr("last_send_verify_code_time");
        String verifyMobileNumber = getSessionAttr("verify_mobile_number"); // 是谁发的验证码

        if (StrKit.isBlank(storedVerifyCode) || sendTime == null) {
            // Session中没有验证码或发送时间，可能从未发送过，或Session已失效/过期
            return MyRet.fail("请先获取验证码或验证码已失效");
        }
        
        // 是不是该手机号发送的验证码
        if (!verifyMobileNumber.equals(mobileNumber)) {
            return MyRet.fail("手机号校验失败！");
        }

        // 校验有效期
        long currentTime = System.currentTimeMillis();
        if (currentTime - sendTime > VERIFY_CODE_EXPIRATION_TIME) {
            // 验证码已过期
            // 可以在这里清除Session中的验证码，防止不必要的存储
            removeSessionAttr("verify_code");
            removeSessionAttr("last_send_verify_code_time");
            return MyRet.fail("验证码已过期，请重新获取");
        }

        // 校验用户输入的验证码是否与Session中存储的一致
        if (!userVerifyCode.equals(storedVerifyCode)) {
            return MyRet.fail("验证码错误");
        }

        removeSessionAttr("verify_code");
        
        return MyRet.ok("验证码校验通过");
    }
}
