package com.chinaweal.aiccs.org.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.chinaweal.aiccs.common.util.RSAUTil;
import com.chinaweal.aiccs.common.util.SM4Utils;
import com.chinaweal.aiccs.common.util.StringUtils;
import com.chinaweal.aiccs.org.entity.UserSupInfo;
import com.chinaweal.aiccs.org.service.IUserSupInfoService;
import com.chinaweal.aiccs.redis.RedisService;
import com.chinaweal.youfool.framework.springboot.exception.custom.BusinessException;
import com.chinaweal.youfool.framework.springboot.rest.RestResult;
import com.chinaweal.youfool.framework.sso.util.SSOUtil;
import com.github.xiaoymin.knife4j.annotations.ApiSupport;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.util.Base64;

/**
 * 用户APP信息管理
 */
@Api(tags = "用户APP信息管理")
@ApiSupport(author = "system")
@RestController
@RequestMapping("/usersapp")
@Slf4j
public class TUsersappController {

    @Autowired
    private IUserSupInfoService userSupInfoService;

    @Resource
    private RedisService redisService;

    @Value("${redis-usersapp-privatekey.expire:300}")
    private int privateKeyExpire;
    @Value("${oauth2.sm4.key}")
    private String sm4Key;

    private static final String REDIS_PRIVATE_KEY_PREFIX = "usersapp:rsa:privatekey:";

    private static final String RSA_COOKIE_KEY = "usersapprsa";

    /**
     * 接口1：检查用户对应的UserSupInfo中有没有身份证号和手机号码的记录
     *
     * @param request 请求
     * @return true-有完整记录，false-没有完整记录
     */
    @GetMapping("/check")
    @ApiOperation(value = "检查用户是否有身份证号和手机号码记录")
    public RestResult<Boolean> checkUserInfo(HttpServletRequest request) {
        String userId = SSOUtil.getUser().getPrimaryKey();
        if (StringUtils.isBlank(userId)) {
            return RestResult.error(com.chinaweal.youfool.framework.springboot.rest.ResultCode.USER_NOT_LOGGED_IN);
        }
        UserSupInfo byId = userSupInfoService.getById(userId);

        return RestResult.ok(byId != null && StringUtils.isNotBlank(byId.getMobileEnc()) && StringUtils.isNotBlank(byId.getIdcardEnc()));
    }

    /**
     * 接口2：获取RSA密钥对
     * 公钥返回给前端，私钥存储在Redis中
     * Redis的key后缀使用cookie中的值
     *
     * @param request  请求
     * @param response response
     * @return 公钥
     */
    @GetMapping("/getPublicKey")
    @ApiOperation(value = "获取RSA公钥")
    public RestResult<String> getRsaPublicKey(HttpServletRequest request, HttpServletResponse response) {
        String cookieValue = getCookieValue(request, RSA_COOKIE_KEY);
        if (StringUtils.isBlank(cookieValue)) {
            cookieValue = StringUtils.getUUID();
            setCookieValue(response, RSA_COOKIE_KEY, cookieValue);
        }

        try {
            KeyPairGenerator keyPairGen = KeyPairGenerator.getInstance("RSA");
            keyPairGen.initialize(1024, new java.security.SecureRandom());
            KeyPair keyPair = keyPairGen.generateKeyPair();
            RSAPrivateKey privateKey = (RSAPrivateKey) keyPair.getPrivate();
            RSAPublicKey publicKey = (RSAPublicKey) keyPair.getPublic();

            String publicKeyString = Base64.getEncoder().encodeToString(publicKey.getEncoded());
            String privateKeyString = Base64.getEncoder().encodeToString(privateKey.getEncoded());

            // 私钥存储到Redis，key后缀使用cookie值
            String redisKey = REDIS_PRIVATE_KEY_PREFIX + cookieValue;
            redisService.set(redisKey, privateKeyString, privateKeyExpire);

            return RestResult.ok(publicKeyString);
        } catch (NoSuchAlgorithmException e) {
            log.error("生成RSA密钥对失败", e);
            throw new BusinessException("生成RSA密钥对失败");
        }
    }

    /**
     * 接口3：用户账号信息设置接口
     * 用户传入身份证号（RSA密文）、手机号（RSA密文）
     * 使用RSA解密后得到明文，然后使用SM4加密存储到数据库，同时计算MD5摘要用于去重
     * 查询UserSupInfo表，确保数据是唯一的
     * 如果不唯一，则抛出BusinessException说明信息已被占用
     * 否则创建或更新UserSupInfo的记录
     *
     * @param identityNoEncrypted 身份证号密文
     * @param mobileEncrypted     手机号密文
     * @param request             请求
     * @return 设置结果
     */
    @PostMapping("/setUserInfo")
    @ApiOperation(value = "设置用户账号信息")
    public RestResult<Void> setUserInfo(
            @ApiParam("身份证号密文") @RequestParam String identityNoEncrypted,
            @ApiParam("手机号密文") @RequestParam String mobileEncrypted,
            HttpServletRequest request) {
        String userId = SSOUtil.getUser().getPrimaryKey();
        if (StringUtils.isEmpty(userId)) {
            return RestResult.error(com.chinaweal.youfool.framework.springboot.rest.ResultCode.USER_NOT_LOGGED_IN);
        }

        String cookieValue = getCookieValue(request, RSA_COOKIE_KEY);
        if (StringUtils.isEmpty(cookieValue)) {
            throw new BusinessException("Cookie不存在或已过期");
        }

        // 从Redis获取私钥
        String redisKey = REDIS_PRIVATE_KEY_PREFIX + cookieValue;
        String privateKeyString = redisService.get(redisKey);
        if (StringUtils.isEmpty(privateKeyString)) {
            throw new BusinessException("传输加密的密钥已过期，请刷新页面重新获取");
        }

        try {
            // 使用RSA解密前端传来的数据
            String identityNo = RSAUTil.decrypt(identityNoEncrypted, privateKeyString);
            String mobile = RSAUTil.decrypt(mobileEncrypted, privateKeyString);
            identityNo = StringUtils.trimToEmpty(identityNo);
            mobile = StringUtils.trimToEmpty(mobile);

            // 计算MD5摘要（用于去重）
            String identityNoAbstr = DigestUtils.md5DigestAsHex(identityNo.getBytes(StandardCharsets.UTF_8));
            String mobileAbstr = DigestUtils.md5DigestAsHex(mobile.getBytes(StandardCharsets.UTF_8));

            // 查询是否存在相同的身份证号或手机号（排除当前用户）
//            LambdaQueryWrapper<UserSupInfo> wrapper = new LambdaQueryWrapper<>();
//            wrapper.and(w -> w
//                    .eq(UserSupInfo::getIdcardAbstr, identityNoAbstr)
//                    .or()
//                    .eq(UserSupInfo::getMobileAbstr, mobileAbstr)
//            ).ne(UserSupInfo::getUserid, userId);
//
//            long count = userSupInfoService.count(wrapper);
//            if (count > 0) {
//                throw new BusinessException("身份证号或手机号已被其他用户占用");
//            }

            // 使用SM4加密后存储到数据库
            String identityNoEnc = SM4Utils.encrypt(identityNo, sm4Key);
            String mobileEnc = SM4Utils.encrypt(mobile, sm4Key);

            // 查询当前用户的UserSupInfo记录
            UserSupInfo existUser = userSupInfoService.getById(userId);

            if (existUser != null) {
                // 更新记录
                existUser.setIdcardEnc(identityNoEnc);
                existUser.setIdcardAbstr(identityNoAbstr);
                existUser.setMobileEnc(mobileEnc);
                existUser.setMobileAbstr(mobileAbstr);
                userSupInfoService.updateById(existUser);
            } else {
                // 创建新记录
                UserSupInfo newUser = new UserSupInfo();
                newUser.setUserid(userId);
                newUser.setIdcardEnc(identityNoEnc);
                newUser.setIdcardAbstr(identityNoAbstr);
                newUser.setMobileEnc(mobileEnc);
                newUser.setMobileAbstr(mobileAbstr);
                userSupInfoService.save(newUser);
            }

            // 删除Redis中的私钥
            redisService.remove(redisKey);

            return RestResult.ok();
        } catch (BusinessException e) {
            throw e;
        } catch (Exception e) {
            log.error("设置用户账号信息失败", e);
            throw new BusinessException("解密失败或处理异常");
        }
    }

    /**
     * 获取Cookie中的值
     */
    private String getCookieValue(HttpServletRequest request, String cookieKey) {
        Cookie[] cookies = request.getCookies();
        if (cookies != null) {
            for (Cookie cookie : cookies) {
                if (cookieKey.equals(cookie.getName())) {
                    return cookie.getValue();
                }
            }
        }
        return null;
    }

    /**
     * 设置cookie
     *
     * @param response    response
     * @param cookieKey   cookieKey
     * @param cookieValue cookie值
     */
    private void setCookieValue(HttpServletResponse response, String cookieKey, String cookieValue) {
        Cookie cookie = new Cookie(cookieKey, cookieValue);
        cookie.setPath("/aiccs-api");
        response.addCookie(cookie);
    }
}
