package cc.mrbird.febs.auth.configure;

import cc.mrbird.febs.auth.entity.OauthClientDetails;
import cc.mrbird.febs.auth.service.OauthClientDetailsService;
import cn.cttic.crypto.bean.DecryptCodeBean;
import cn.cttic.crypto.bean.EncryptCodeBean;
import cn.cttic.crypto.bean.EncryptCrcBean;
import cn.cttic.crypto.service.SMCryptoService;
import cn.cttic.crypto.service.impl.SMCryptoServiceImpl;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.ruoyi.common.core.domain.vo.TransportRequest;
import com.ruoyi.common.core.exception.BusinessException;
import com.ruoyi.common.redis.service.RedisService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.crypto.keygen.BytesKeyGenerator;
import org.springframework.security.crypto.keygen.KeyGenerators;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import org.springframework.web.client.RestTemplate;

import org.apache.commons.codec.binary.Base64;

import static com.ruoyi.common.core.constant.HttpStatus.UNAUTHORIZED;
import static com.ruoyi.common.core.constant.ThirdLoginConstants.IS_THIRD;
import static com.ruoyi.common.core.constant.ThirdLoginConstants.THIRD_FLAG;
import static com.ruoyi.common.core.utils.ServletUtils.renderString;
import static org.springframework.security.web.authentication.www.BasicAuthenticationConverter.AUTHENTICATION_SCHEME_BASIC;

@Slf4j
@Component
public class DecryptThirdTokenFilter extends OncePerRequestFilter {

    @Value("${crypt.privateKey}")
    private String privateKey;
    private static final String PUBLIC_KEY = "MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEk0pEoaFohIHRFgEkOglHRRNkR9SWpaVSTslPShtK7GD/+uw2TwZjUzgIhBXFUBYx2pdTVk314SEgtygNk/HSZA==";
    private final Gson gson = new Gson();
    // 新增加密服务实例（在类顶部）
    private final SMCryptoService smCryptoService = new SMCryptoServiceImpl();
    private static final String encrypt_key = "8iot1blDJgNK36Do"; // 部解密省加密
    private static final String decrypt_key = "QLdQIASYMlT9SUUg"; //部加密省解密
    private static final BytesKeyGenerator DEFAULT_TOKEN_GENERATOR = KeyGenerators.secureRandom(20);
    private static final Charset US_ASCII = Charset.forName("US-ASCII");
    @Autowired
    private RedisService redisService;
    private static final String CACHE_CLIENT_KEY = "data_exchange_client";
    @Autowired
    private OauthClientDetailsService oauthClientDetailsService;

    // 新增TransportClient依赖
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
//        String requestBody = IOUtils.toString(request.getInputStream(), "UTF-8");
//        log.info("=== 请求头信息 ===");
//        Enumeration<String> headerNames = request.getHeaderNames();
//        while (headerNames.hasMoreElements()) {
//            String headerName = headerNames.nextElement();
//            log.info("{}: {}", headerName, request.getHeader(headerName));
//        }

        // 使用支持body缓存的请求包装器
        HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(request);
        String requestBody = requestWrapper.getRequestBody();
        log.info("=== 请求体信息 ===requestBody: {}", requestBody);
        // 非第三方获取token直接放行
        String isThird = request.getHeader(IS_THIRD);
        // 判断是否第三方请求（满足任一条件即可）
        boolean isThirdRequest = THIRD_FLAG.equals(isThird)
                || (requestBody.contains("Header") && requestBody.contains("Body"));

        if (!isThirdRequest) {
            requestWrapper.setBody(requestBody);
            chain.doFilter(requestWrapper, response);
            return;
        }
        // 第三方获取token,解密认证信息
//        HeaderMapRequestWrapper requestWrapper;
        try {
            if (THIRD_FLAG.equals(isThird)) {
                String header = request.getHeader(HttpHeaders.AUTHORIZATION);
                if (header == null) {
                    throw new BadCredentialsException("No basic authentication token");
                } else {
                    header = header.trim();
                    if (!StringUtils.startsWithIgnoreCase(header, AUTHENTICATION_SCHEME_BASIC)) {
                        throw new BadCredentialsException("Need basic authentication token");
                    }
                    if (header.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
                        throw new BadCredentialsException("Empty basic authentication token");
                    }

                    String token = header.substring(6);
                    SM2 sm2 = SmUtil.sm2(privateKey, null);
                    String decryptStr;
                    try {
                        decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(token, KeyType.PrivateKey));
                    } catch (Exception e) {
                        throw new BusinessException("解密失败");
                    }
                    // 先打印原始请求体用于调试
//                    log.info("原始请求体内容：{}", requestBody);
//                  JSONObject obj = handleFormURLEncoded(requestBody);
//                  String grantType = obj.getString("grant_type");

                    requestWrapper.setBody(requestBody);  // 使用支持body修改的请求包装器
                    requestWrapper.addHeader(HttpHeaders.AUTHORIZATION, AUTHENTICATION_SCHEME_BASIC + " " + decryptStr);
                }
            } else {
                    // 获取请求体内容（新增部分）
                    TransportRequest transportRequest = gson.fromJson(requestBody, TransportRequest.class);
                    String body = transportRequest.getBody();
                    String decryptBodyStr = "";
                    if (!StringUtils.isEmpty(body)) {
                        decryptBodyStr = decryptBody(body);
                    }
                    JSONObject bodyObject = JSONObject.parseObject(decryptBodyStr);

                    String user = String.valueOf(bodyObject.get("user"));
                    String password = String.valueOf(bodyObject.get("password"));
                    // 1. 构造加密字符串
                    String basicCredentials = bodyObject.get("user") + ":" + bodyObject.get("password");
                    String base64Credentials = Base64.encodeBase64String(basicCredentials.getBytes());

                    // 2. SM2加密（需根据实际SM2工具类实现）
                    SM2 sm2 = SmUtil.sm2(null, PUBLIC_KEY);
                    String encrypted =  sm2.encryptBcd(base64Credentials, KeyType.PublicKey);

                    // 3. 构建Authorization头
                    String header = "Basic " + encrypted;
                    // String header = request.getHeader(HttpHeaders.AUTHORIZATION);
                    if (header == null) {
                        throw new BadCredentialsException("No basic authentication token");
                    } else {
                        header = header.trim();
                        if (!StringUtils.startsWithIgnoreCase(header, AUTHENTICATION_SCHEME_BASIC)) {
                            throw new BadCredentialsException("Need basic authentication token");
                        }
                        if (header.equalsIgnoreCase(AUTHENTICATION_SCHEME_BASIC)) {
                            throw new BadCredentialsException("Empty basic authentication token");
                        }

                        String token = header.substring(6);
                        sm2 = SmUtil.sm2(privateKey, null);
                        String decryptStr;
                        try {
                            decryptStr = StrUtil.utf8Str(sm2.decryptFromBcd(token, KeyType.PrivateKey));
                        } catch (Exception e) {
                            throw new BusinessException("解密失败");
                        }
                        // 构造新的表单格式请求体，确保后续能解析到参数

                        requestWrapper.addHeader(HttpHeaders.AUTHORIZATION, AUTHENTICATION_SCHEME_BASIC + " " + decryptStr);
                        requestWrapper.addHeader("Content-Type", "application/x-www-form-urlencoded");
                        String grantType = "client_credentials"; // 从请求体解析出的值
                        requestWrapper.setParameter("grant_type", grantType);
                        String newRequestBody = "grant_type=client_credentials";
                        requestWrapper.setBody(newRequestBody);

                        // 自定义构建响应体
                        // {"Header":{"SerialNum":"50000020250508000000000001","SystemId":"500000","Source":"500000","Target":"999999","Version":"V1","IPCType":"YZ1001","ReqTime":"20250508135739","CRC":"A1F38CE896264C3068192AD4843FC37CEDE78B26200DACFA979FCBF7FCCF5AF0","ReqType":"0"},"Body":"7KIwA8zAIvlxH0QTg7C2ZXeId7H3Pt/TedCnX5sj4Anf7Dtw9Y4LfL/swf5ep0KM"}
                        // {"Header":{"SerialNum":"50000020250508000000000001","SystemId":"500000","Source":"500000","Target":"999999","Version":"V1","IPCType":"YZ1001","ReqTime":"20250508135739","CRC":"114450A70B27EAEBCDE152BDEDE4F3D6B3C98E475495D48532D12A80BC5F6BB5","ReqType":"1","Token":"","Code":"0000","Message":"成功"},"Body":"xgvlqfCKIZGDzRWDcYQG9DgiUXvLoy81MhUw/kKy2YOftR+vWHyEmupKgGMrF2Y4fAqFdu7tcbkDA2zApx/aBF1stmq8SRQVb+FgSy9Mu9BkOwPpPBavSI1V2UPW/5DTjayayrd9HDfFc3nKC7/6LOzQAJ2VxdUYXvdBPhKd6mNgmOqKSej4xmg+s5qg5u/5WUL20yXe4vgis4YN21N1Dg=="}
                        Map<String, Object> tokenMap = new HashMap<>();
                        Map<String,Object>  crcBodyMap = new HashMap<>();
                        if (redisService.hasKey(user)) {
                           crcBodyMap =redisService.getCacheMap(user);
                            for (Map.Entry<String, Object> entry : crcBodyMap.entrySet()) {
                                String key = entry.getKey();   // 获取键（"header"或"body"）
                                String value = String.valueOf(entry.getValue()); // 获取对应值
                                transportRequest.getHeader().setCrc(key);
                                tokenMap.put("token", value);
                                String tokenBody = gson.toJson(tokenMap);
                                transportRequest.setBody(encryptBody(tokenBody));
                                log.info("=== 返回验证token（未加密redis） ===token: {}", value);
                            }
                        } else {
                            String sourceType = "data_exchange_client";
                            String tokenValue = new String(Base64.encodeBase64URLSafe(DEFAULT_TOKEN_GENERATOR.generateKey()), US_ASCII);
                            String tokenValueBase64 = Base64.encodeBase64String((sourceType + "_" + tokenValue).getBytes(StandardCharsets.UTF_8));
                            tokenMap.put("token", encryptBody(tokenValueBase64));
                            log.info("=== 返回验证token（未加密mysql） ===token: {}", encryptBody(tokenValueBase64));
                            String tokenBody = gson.toJson(tokenMap);
                            String crc = calculateSM3(tokenBody);
                            String responseBody = encryptBody(tokenBody);
                            redisService.setCacheMapValue(user, crc, encryptBody(tokenValueBase64));
                            redisService.expire(user, 24 * 60 * 60);
                            transportRequest.getHeader().setCrc(crc);
                            transportRequest.setBody(responseBody);
                            OauthClientDetails client = this.oauthClientDetailsService.findById(user);
                            client.setAccessTokenInfo(encryptBody(tokenValueBase64));
                            oauthClientDetailsService.updateOauthClientDetails(client);
                        }

                        transportRequest.getHeader().setReqType("1");
                        transportRequest.getHeader().setToken("");
                        transportRequest.getHeader().setCode("0000");
                        transportRequest.getHeader().setMessage("成功");
                        // 替换直接写response的方式
                        String transportResponse = gson.toJson(transportRequest);
                        log.info("=== 响应体信息 ===transportResponse: {}", transportResponse);
                        renderString(response, HttpServletResponse.SC_OK, transportResponse);
                        return;
                    }
            }
            // 打印请求头和请求体
//            log.info("=== 请求头信息 ===");
//            headerNames = requestWrapper.getHeaderNames();
//            while (headerNames.hasMoreElements()) {
//                String headerName = headerNames.nextElement();
//                log.info("{}: {}", headerName, requestWrapper.getHeader(headerName));
//            }
//
//            log.info("=== 最后请求体信息 ===");
//            log.info("Body: {}", requestWrapper.getRequestBody());

        } catch (BadCredentialsException | BusinessException e) {
            log.error(e.getMessage());
            renderString(response, UNAUTHORIZED, e.getMessage());
            return;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            response.setStatus(UNAUTHORIZED);
            return;
        }

        // 在设置完请求体后添加日志验证
        log.info("Parsed grant_type: {}", requestWrapper.getParameter("grant_type"));
        chain.doFilter(requestWrapper, response);
    }

    // SM3哈希计算
    public String calculateSM3(String data) {
        EncryptCrcBean encryptCrcBean = new EncryptCrcBean();
        encryptCrcBean.setPass(data);
        String cipherText_crc = smCryptoService.encryptCrc(encryptCrcBean);
        return cipherText_crc;
    }

    // SM4加密Body（ECB模式）
    public String encryptBody(String plainText) throws Exception {
        EncryptCodeBean encryptCodeBean = new EncryptCodeBean();
        encryptCodeBean.setSecretKey(encrypt_key);
        encryptCodeBean.setPass(plainText);
        String cipherText = smCryptoService.encrypt_Body(encryptCodeBean);
        return cipherText;
    }
    // SM4解密Body（ECB模式）
    public String decryptBody(String plainText) throws Exception {
        DecryptCodeBean encrypt2 = new DecryptCodeBean();
        encrypt2.setSecretKey(decrypt_key);
        encrypt2.setPass(plainText);
        String cipherText = smCryptoService.decrypt_Body(encrypt2);
        return cipherText;
    }

    private JSONObject handleFormURLEncoded(String param) {
        JSONObject jsonObject = new JSONObject();
        for (String s : param.split("&")) {
            String[] split = s.split("=");
            jsonObject.put(split[0], split[1]);
        }
        return jsonObject;
    }
}
