//package com.backendsys.service.System;
//
//import cn.hutool.json.JSONUtil;
//import com.backendsys.config.Kaptcha.KaptchaUtil;
//import com.backendsys.exception.CustException;
//import com.backendsys.modules.common.config.redis.utils.RedisUtil;
//import com.backendsys.modules.common.config.security.entity.SecurityUserInfo;
//import com.backendsys.modules.common.config.security.utils.TokenUtil;
//import com.backendsys.modules.system.dao.SysUserInfoDao;
//import com.backendsys.entity.System.SysUserDTO;
//import com.backendsys.service.SDKService.SDKTencent.SDKTencentSMSService;
//import com.backendsys.utils.CountUtil;
//import com.backendsys.utils.UserUtils;
//import com.backendsys.utils.response.ResultEnum;
//import com.backendsys.mapper.System.SysUserMapper;
//import com.backendsys.modules.common.config.security.utils.JwtUtil;
//import com.google.code.kaptcha.Producer;
//import jakarta.servlet.ServletOutputStream;
//import jakarta.servlet.http.HttpServletRequest;
//import jakarta.servlet.http.HttpServletResponse;
//import org.redisson.api.RLock;
//import org.redisson.api.RedissonClient;
//import org.springframework.beans.factory.annotation.Autowired;
//import org.springframework.beans.factory.annotation.Value;
//import org.springframework.context.annotation.Lazy;
//import org.springframework.core.env.Environment;
//import org.springframework.data.redis.core.StringRedisTemplate;
//import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//
//import javax.imageio.ImageIO;
//import java.awt.image.BufferedImage;
//import java.io.ByteArrayOutputStream;
//import java.io.IOException;
//import java.time.LocalDateTime;
//import java.util.*;
//import java.util.concurrent.TimeUnit;
//
//@Service
//public class SysAuthServiceImpl implements SysAuthService {
//
//    @Autowired
//    private Environment env;
//    @Value("${tencent.sms.debug}")
//    private String SMS_DEBUG;
//    @Value("${REDIS_LOGIN_TOKEN_PREFIX}")
//    private String REDIS_LOGIN_TOKEN_PREFIX;
//
//    @Autowired
//    private CountUtil countUtil;
//
//    @Lazy
//    @Autowired
//    RedissonClient redissonClient;
//
//    @Autowired
//    private RedisUtil redisUtil;
//
//    @Autowired
//    private TokenUtil tokenUtil;
//
//    @Autowired
//    private StringRedisTemplate stringRedisTemplate;
//
//    @Autowired
//    private SysUserMapper sysUserMapper;
//
//    @Autowired
//    private JwtUtil jwtUtil;
//
//    @Value("${TOKEN_DURATION_SYSTEM}")
//    private Long TOKEN_DURATION_SYSTEM;
//
//    @Value("${spring.config.name}")
//    private String configName;
//
//    @Value("${CAPTCHA_DURATION}")
//    private Long CAPTCHA_DURATION;
//
//    @Autowired
//    private Producer captchaProducer;
//
//    @Autowired
//    private SDKTencentSMSService sdkTencentSMSService;
//
//    @Autowired
//    private SysUserInfoDao sysUserInfoDao;
//
//    /**
//     * 渲染 图形验证码
//     */
//    public void renderCaptcha(HttpServletRequest request, HttpServletResponse response) throws RuntimeException, IOException {
//        byte[] captchaChallengeAsJpeg = null;
//        ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();
//        try {
//            String createText = captchaProducer.createText();
//            // 获得当前 (UA + IP) 生成的 Key
//            String captchaRedisKey = KaptchaUtil.getKaptchaKey(request);
//            // 保存 验证码字符串 到 redis 中
//            stringRedisTemplate.opsForValue().set(captchaRedisKey, createText, this.CAPTCHA_DURATION, TimeUnit.MILLISECONDS);
//            // 返回 BufferedImage 对象并转为 byte 写入到 byte 数组中
//            BufferedImage challenge = captchaProducer.createImage(createText);
//            ImageIO.write(challenge, "jpg", jpegOutputStream);
//            //
//        } catch (Exception e) {
//            response.sendError(HttpServletResponse.SC_NOT_FOUND);return;
//        }
//        // 定义response输出类型为image/jpeg类型，使用response输出流输出图片的byte数组
//        captchaChallengeAsJpeg = jpegOutputStream.toByteArray();
//        response.setHeader("Cache-Control", "no-store");
//        response.setHeader("Pragma", "no-cache");
//        response.setDateHeader("Expires", 0);
//        response.setContentType("image/jpeg");
//        ServletOutputStream responseOutputStream = response.getOutputStream();
//        responseOutputStream.write(captchaChallengeAsJpeg);
//        responseOutputStream.flush();
//        responseOutputStream.close();
//    }
//
//    // [Method] 判断图形验证码是否正确
//    private Boolean isCaptchaValid(String captcha, String captchaRedisKey) {
//        // 如果不是本地开发环境，则执行以下判断
//        String profileActive = env.getProperty("spring.profiles.active");
//        if (!("local".equals(profileActive))) {
//            // 判断验证码是否正确 (是否与Redis中的验证码匹配) (测试环境忽略)
//            String captchaRedisValue = stringRedisTemplate.opsForValue().get(captchaRedisKey);
//            if (captchaRedisValue == null || !captchaRedisValue.equalsIgnoreCase(captcha)) {
//                return false;
//            }
//        }
//        return true;
//    }
//
//    // [Method] 判断密码是否正确
//    private Boolean isUserPasswordValid(Map<String, Object> userDTO, String password) {
//        if (userDTO == null) return false;
//        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//        return encoder.matches(password, (String) userDTO.get("password"));
//    }
//
//    /**
//     * [封装] 登录成功回调信息
//     */
//    private Map<String, Object> loginSuccess(HttpServletRequest request, SysUserDTO sysUserDTO) {
//
//        String uuid = String.valueOf(UUID.randomUUID());
//        Long userId = sysUserDTO.getUser_id();
//        Map<String, Object> sysUserDetail = sysUserMapper.queryUserDetail(userId);
//
//        // 判断用户是否已审核
//        Integer auditStatus = (Integer) sysUserDetail.get("audit_status");
//        if (auditStatus == 1) throw new CustException("请等待管理员审核");
//        if (auditStatus == -1) throw new CustException("审核未通过，请联系客服获取详细信息");
//
//        // [Redis] 删除旧 Redis Key
//        String old_uuid = (String) sysUserDetail.get("last_login_uuid");
//        if (old_uuid != null) stringRedisTemplate.delete("token:id:" + old_uuid);
//
//        // 3.判断用户 status 是否启用
//        Object status = sysUserDetail.get("status");
//        if (status != null && (Integer) status == -1) throw new CustException("该用户已被禁用");
//
//        // 4.格式化 modules: [{ id: 1, module_code: "xxx" }] 转为 ["1.x.x", "2.x.x"] (减少 Token 长度)
//        List<Map<String, Object>> roles = (List<Map<String, Object>>) sysUserDetail.get("roles");
//        if (roles != null) {
//            List<String> modules = UserUtils.extractModuleCodes(roles);
//            roles.forEach(role -> role.remove("module_ids"));
//            sysUserDetail.put("modules", modules);
//            sysUserDetail.put("roles", roles);
//        }
//
//        //// x.判断用户 del_flag 是否逻辑删除
//        //Object del_flag = sysUser.get("del_flag");
//        //if (del_flag != null && (Integer) del_flag == 1) {
//        //    return Result.error(ResultEnum.INVALID_CREDENTIALS.getCode(), "该用户不存在 (flag)");
//        //}
//
//        // 5.生成 Token 并存入 Redis
//        // 生成 Token 过期时间 (存入Token/带出Result返回值)
//        Boolean isRemember = sysUserDTO.getIs_remember();
//        Long tokenDuration = (isRemember != null && isRemember) ? TOKEN_DURATION_SYSTEM * 7 : TOKEN_DURATION_SYSTEM;
//        Date tokenExpiration = new Date((new Date()).getTime() + tokenDuration);
//        sysUserDetail.put("token_expiration", tokenExpiration);
//
//        // 生成 Token
//        sysUserDetail.put("last_login_uuid", uuid);
//
////        Map<String, Object> userInfo = new LinkedHashMap<>(sysUserDetail);
////        userInfo.remove("modules");
////        String token = jwtUtil.createSystemToken(userInfo);
//
//        SecurityUserInfo securityUserInfo = JSONUtil.toBean(JSONUtil.parseObj(sysUserDetail), SecurityUserInfo.class);
//        String token = jwtUtil.createSystemJwtToken(securityUserInfo);
//
//        // 存入 Redis：Token、Token过期时间
//        String tokenRedisKey = REDIS_LOGIN_TOKEN_PREFIX + uuid;
//        stringRedisTemplate.opsForValue().set(tokenRedisKey, token, tokenDuration, TimeUnit.MILLISECONDS);
//
//        // 6.[更新] 用户最后登录时间、登录IP
//        SysUserDTO sysUserLastlogin = new SysUserDTO();
//        sysUserLastlogin.setUser_id(userId);
//        sysUserLastlogin.setLast_login_ip(request.getRemoteAddr());
//        sysUserLastlogin.setLast_login_uuid(uuid);
//        LocalDateTime now = LocalDateTime.now();
//        String formattedDateTime = now.toString();
//        sysUserLastlogin.setLast_login_time(formattedDateTime);
//        sysUserMapper.updateUserInfo(sysUserLastlogin);
//
//        // 7.[格式化] 将 Token 拼接到输出结果
//        Map<String, Object> result = new LinkedHashMap<>(sysUserDetail);
//        result.remove("del_flag");
//        result.put("token", token);
//
//        return result;
//    }
//
//    /**
//     * 登录 系统用户 (用户名)
//     * @param sysUserDTO(username, password, captcha)
//     * @return { token, sysUser }
//     */
//    @Override
//    @Transactional
//    public Map<String, Object> login(HttpServletRequest request, SysUserDTO sysUserDTO) {
//
//        String username = sysUserDTO.getUsername();
//        String password = sysUserDTO.getPassword();
//        String captcha = sysUserDTO.getCaptcha();
//
//        // 判断是否处于 5次的错误状态
//        countUtil.checkErrorStatus("login-error", username);
//
//        // [Redis] 验证码临时密钥
//        String captchaRedisKey = KaptchaUtil.getKaptchaKey(request);
//
//        // [Method] 判断验证码是否正确
//        if (!isCaptchaValid(captcha, captchaRedisKey)) {
//            stringRedisTemplate.delete(captchaRedisKey);
//            throw new CustException("验证码错误", ResultEnum.INVALID_CREDENTIALS.getCode());
//        }
//
//        // [Method] 判断 用户 是否存在 && 密码是否正确
//        Map<String, Object> sysUserSimple = sysUserMapper.queryUserByIdOrName(null, username, null, null);
//        if (sysUserSimple != null) {
//            sysUserDTO.setUser_id((Long) sysUserSimple.get("id"));
//        }
//        if (!(sysUserSimple != null && isUserPasswordValid(sysUserSimple, password))) {
//            stringRedisTemplate.delete(captchaRedisKey);
//            // 添加错误标记 (2分钟内错误5次，则出现提示)
//            countUtil.setErrorCount("login-error", username);
//            //
//            throw new CustException("用户名或密码错误", ResultEnum.INVALID_CREDENTIALS.getCode());
//        }
//
//        // 1.作废验证码密钥
//        stringRedisTemplate.delete(captchaRedisKey);
//
//        // [登录成功]
//        Map<String, Object> result = loginSuccess(request, sysUserDTO);
//
//        return result;
//    }
//
//    /**
//     * 登录 系统用户 (手机号码)
//     * @param sysUserDTO(phone, phone_valid_code)
//     */
//    @Override
//    @Transactional
//    public Map<String, Object> loginWithPhone(HttpServletRequest request, SysUserDTO sysUserDTO) {
//
//        String phone = sysUserDTO.getPhone();
//        Integer phoneAreaCode = sysUserDTO.getPhone_area_code();
//        Integer phoneValidCode = sysUserDTO.getPhone_valid_code();
//
//        // 判断是否处于 5次的错误状态
//        countUtil.checkErrorStatus("login-error", phone);
//
//        // 判断手机验证码是否正确
//        String redisKey = "sms-login-" + phone;
//        Integer smsCode = redisUtil.getCacheObject(redisKey);
//        System.out.println("smsCode: " + smsCode);
//
//        // 判断短信验证码是否错误
//        if ("false".equals(SMS_DEBUG) && (smsCode == null || !smsCode.equals(phoneValidCode))) {
//            // 添加错误标记 (2分钟内错误5次，则出现提示)
//            countUtil.setErrorCount("login-error", phone);
//            throw new CustException("短信验证码错误", ResultEnum.INVALID_CREDENTIALS.getCode());
//        }
//
//        // 判断手机号是否存在
//        Map<String, Object> sysUserSimple = sysUserMapper.queryUserByIdOrName(null, null, phone, phoneAreaCode);
//         if (sysUserSimple == null) {
//            throw new CustException("手机号码不存在", ResultEnum.INVALID_CREDENTIALS.getCode());
//        } else {
//            // 登录成功，销毁短信验证码
//            redisUtil.delete(redisKey);
//
//            // 登录成功回调
//            sysUserDTO.setUser_id((Long) sysUserSimple.get("id"));
//            Map<String, Object> result = loginSuccess(request, sysUserDTO);
//            return result;
//        }
//    }
//
//    /**
//     * 注册 系统用户
//     * @param sysUserDTO
//     * @return { user_id }
//     */
//    @Override
//    @Transactional
//    public Map<String, Object> registerUser(HttpServletRequest request, SysUserDTO sysUserDTO) {
//
//        //// 如果可以获得当前 token 的 id，那以后创建分布式锁时，可以按照 userId 来创建锁
//        //System.out.println("tokenService.getLoginUUID() = " + tokenService.getLoginUUID());
//
//        RLock lock = redissonClient.getLock("registerUser");
//        try { lock.tryLock(3, TimeUnit.SECONDS);
//
//            // -- 校验-----------------------------------------------------------------
//            // 判断图形验证码是否正确
//            String captcha = sysUserDTO.getCaptcha();
//            String captchaRedisKey = KaptchaUtil.getKaptchaKey(request);
//            if (!isCaptchaValid(captcha, captchaRedisKey)) {
//                stringRedisTemplate.delete(captchaRedisKey);
//                throw new CustException("图形验证码错误");
//            }
//            // 如果是用手机号注册，则还需判断短信验证码是否正确
//            if (sysUserDTO.getPhone() != null) {
//
//                Integer phoneValidCode = sysUserDTO.getPhone_valid_code();
//
//                String redisKey = "sms-register-" + sysUserDTO.getPhone();
//                Integer smsCode = redisUtil.getCacheObject(redisKey);
//                // System.out.println("smsCode: " + smsCode);
//
//
//                if ("false".equals(SMS_DEBUG) && (smsCode == null || !smsCode.equals(phoneValidCode))) {
//                    throw new CustException("短信验证码错误");
//                }
//
//                // 判断手机号是否已注册
//                Map<String, Object> sysUserSimple1 = sysUserMapper.queryUserByIdOrName(null, null, sysUserDTO.getPhone(), sysUserDTO.getPhone_area_code());
//                if (sysUserSimple1 != null) {
//                    throw new CustException("手机号码已被注册");
//                }
//                // 判断用户名是否已注册
//                Map<String, Object> sysUserSimple2 = sysUserMapper.queryUserByIdOrName(null, sysUserDTO.getUsername(), null, null);
//                if (sysUserSimple2 != null) {
//                    throw new CustException("用户名已被注册");
//                }
//
//                // 判断密钥是否有效
//                String inviteCode = sysUserDTO.getInvite_code();
//                // .. 待做
//
//                // 注册成功，销毁短信验证码
//                redisUtil.delete(redisKey);
//                //
//            }
//
//            // -- 动作 -----------------------------------------------------------------
//
//            // 密码二次加密
//            String password = sysUserDTO.getPassword();
//            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//            String encodedPassword = encoder.encode(password);
//            sysUserDTO.setPassword(encodedPassword);
//
//            // 注册时，默认使用 游客 2L 类型
//            LinkedHashMap<String, Object> role_id_obj = new LinkedHashMap<>();
//            role_id_obj.put("id", 2L);
//            List<LinkedHashMap<String, Object>> convertedList = new ArrayList<>();
//            convertedList.add(role_id_obj);
//
//            // 注册时，仅添加 Username、Password 字段值
//            SysUserDTO registerSysUserDTO = new SysUserDTO();
//            registerSysUserDTO.setUsername(sysUserDTO.getUsername());
//            registerSysUserDTO.setPhone(sysUserDTO.getPhone());
//            registerSysUserDTO.setPhone_valid_code(sysUserDTO.getPhone_valid_code());
//            registerSysUserDTO.setPassword(sysUserDTO.getPassword());
//            registerSysUserDTO.setRoles(convertedList);
//            registerSysUserDTO.setInvite_code(sysUserDTO.getInvite_code());
//
//            sysUserMapper.insertUser(registerSysUserDTO);
//            return Map.of("user_id", registerSysUserDTO.getId());
//
//        } catch (InterruptedException e) { throw new RuntimeException(e);
//        } finally { lock.unlock(); }
//    }
//
//    /**
//     * 忘记密码
//     */
//    @Override
//    @Transactional
//    public Map<String, Object> forgotPassword(SysUserDTO sysUserDTO) {
//        RLock lock = redissonClient.getLock("forgotPassword");
//        try { lock.tryLock(3, TimeUnit.SECONDS);
//
//            // 1.判断短信验证码是否正确
//            Integer phoneValidCode = sysUserDTO.getPhone_valid_code();
//
//            String redisKey = "sms-forgotPassword-" + sysUserDTO.getPhone();
//            Integer smsCode = redisUtil.getCacheObject(redisKey);
////            System.out.println("smsCode: " + smsCode);
//
//            if ("false".equals(SMS_DEBUG) && (smsCode == null || !smsCode.equals(phoneValidCode))) {
//                throw new CustException("短信验证码错误");
//            }
//
//            // 2.判断手机号是否存在
//            Map<String, Object> sysUserSimple = sysUserMapper.queryUserByIdOrName(null, null, sysUserDTO.getPhone(), sysUserDTO.getPhone_area_code());
//            if (sysUserSimple == null) {
//                throw new CustException("手机号码不存在");
//            }
//
//            // 3.更改密码
//            SysUserDTO updateDTO = new SysUserDTO();
//            updateDTO.setUser_id((Long) sysUserSimple.get("id"));
//            // 密码二次加密
//            String password = sysUserDTO.getPassword();
//            BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
//            String encodedPassword = encoder.encode(password);
//            updateDTO.setPassword(encodedPassword);
//
//            sysUserMapper.updateUserPassword(updateDTO);
//
//            // 更改成功，销毁短信验证码
//            redisUtil.delete(redisKey);
//
//            return Map.of("user_id", updateDTO.getUser_id());
//
//        } catch (InterruptedException e) { throw new RuntimeException(e);
//        } finally { lock.unlock(); }
//    }
//
//    /**
//     * 退出登录 (系统用户)
//     */
//    @Override
//    public Map<String, Object> logout(HttpServletRequest request) {
//        String token = tokenUtil.getToken(request);
//        if (token != null && !token.isEmpty()) {
//            // 删除旧的登录缓存
//            tokenUtil.deleteRedisLoginToken(null);
//            return Map.of("message", "退出成功");
//        }
//        throw new CustException(ResultEnum.TOKEN_EMPTY_ERROR.getMessage(), ResultEnum.TOKEN_EMPTY_ERROR.getCode());
//    }
//
//}
