package com.ruoyi.database.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alipay.api.AlipayApiException;
import com.alipay.api.internal.util.AlipayEncrypt;
import com.alipay.api.internal.util.AlipaySignature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.ruoyi.database.exception.BusinessException;
import lombok.extern.slf4j.Slf4j;
import org.checkerframework.checker.units.qual.A;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class AlipayPhoneService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private ObjectMapper objectMapper;

    @Value("${alipay.appId}")
    private String appId;

    @Value("${alipay.privateKey}")
    private String privateKey;

    @Value("${alipay.gateway}")
    private String gateway;


    private final String AES_STR = "LoKBapEj35+bRnC/Rrhe8g==";

    public String getPhoneNumber(String authCode) {
        try {
            // 1. 使用auth_code获取access_token
//            String accessToken = getAccessToken(authCode);
            System.out.println("authCode:" + authCode);
            String charset = "UTF-8";
            String encryptType = "AES";
            //判断是否为加密内容
            boolean isDataEncrypted = !authCode.startsWith("{");
            //3. 解密
            String plainData = null;
            if (isDataEncrypted) {
                try {
                    plainData = AlipayEncrypt.decryptContent(authCode, encryptType, AES_STR, charset);
                    System.out.println("解密:" + plainData);
                } catch (AlipayApiException e) {
                    //解密异常, 记录日志
                    throw new Exception("解密异常");
                }
            } else {
                plainData = authCode;
            }
            // 2. 使用access_token获取用户信息（包含手机号）
            Map<String, Object> responseMap = objectMapper.readValue(plainData, Map.class);
            return responseMap.get("mobile").toString();

        } catch (Exception e) {
            log.error("获取支付宝手机号异常", e);
            throw new BusinessException("ALIPAY_PHONE_ERROR", "获取支付宝手机号异常: " + e.getMessage());
        }
    }

    /**
     * 获取用户id
     */
    private String getOpenId(String authCode) {
        try {
            Map<String, String> params = buildBaseParams();
            params.put("method", "alipay.system.oauth.token");
            params.put("grant_type", "authorization_code");
            params.put("code", authCode);

            log.info("获取access_token请求参数: {}", params);

            String sign = generateSign(params);
            params.put("sign", sign);

            String responseBody = callAlipayApiWithCharset(params);
            log.info("获取access_token响应: {}", responseBody);

            Map<String, Object> responseMap = objectMapper.readValue(responseBody, Map.class);
            Map<String, Object> tokenResponse = (Map<String, Object>) responseMap.get("alipay_system_oauth_token_response");

            if (tokenResponse == null) {
                Map<String, Object> errorResponse = (Map<String, Object>) responseMap.get("error_response");
                if (errorResponse != null) {
                    String subCode = (String) errorResponse.get("sub_code");
                    String subMsg = (String) errorResponse.get("sub_msg");
                    throw new BusinessException("ALIPAY_ACCESS_TOKEN_ERROR",
                            String.format("获取access_token失败[%s]: %s", subCode, subMsg));
                }
                throw new BusinessException("ALIPAY_ACCESS_TOKEN_ERROR", "获取access_token失败: 响应格式错误");
            }

            String accessToken = (String) tokenResponse.get("open_id");
            if (accessToken == null || accessToken.trim().isEmpty()) {
                throw new BusinessException("ALIPAY_ACCESS_TOKEN_ERROR", "获取access_token失败: access_token为空");
            }

            log.info("成功获取access_token: {}", accessToken);
            return accessToken;

        } catch (Exception e) {
            log.error("获取access_token异常", e);
            throw new BusinessException("ALIPAY_ACCESS_TOKEN_ERROR", "获取access_token异常: " + e.getMessage());
        }
    }

    /**
     * 修复后的API调用方法 - 正确处理charset参数
     */
    private String callAlipayApiWithCharset(Map<String, String> params) {
        try {
            // 1. 将charset参数提取到URL查询字符串中
            String charset = params.get("charset");
            params.remove("charset"); // 从业务参数中移除

            // 2. 构建表单数据
            String formData = params.entrySet().stream()
                    .map(entry -> {
                        try {
                            // 使用指定的charset进行编码
                            String encodedValue = URLEncoder.encode(entry.getValue(), charset);
                            return entry.getKey() + "=" + encodedValue;
                        } catch (Exception e) {
                            log.error("参数编码失败: key={}, value={}", entry.getKey(), entry.getValue(), e);
                            return entry.getKey() + "=" + entry.getValue();
                        }
                    })
                    .collect(Collectors.joining("&"));

            // 3. 构建完整的URL，包含charset参数
            String url = gateway + "?charset=" + charset;

            log.debug("支付宝API请求URL: {}", url);
            log.debug("支付宝API请求表单数据: {}", formData);

            // 4. 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.add("User-Agent", "Alipay Client");

            HttpEntity<String> request = new HttpEntity<>(formData, headers);

            // 5. 调用接口
            ResponseEntity<String> response = restTemplate.postForEntity(url, request, String.class);
            return response.getBody();

        } catch (Exception e) {
            log.error("调用支付宝API异常", e);
            throw new BusinessException("ALIPAY_API_ERROR", "调用支付宝API异常: " + e.getMessage());
        }
    }

    /**
     * 修复签名生成方法
     */
    private String generateSign(Map<String, String> params) {
        try {
            // 1. 参数排序
            List<String> keys = new ArrayList<>(params.keySet());
            Collections.sort(keys);

            // 2. 拼接待签名字符串（排除sign参数）
            String signContent = keys.stream()
                    .filter(key -> !"sign".equals(key) && params.get(key) != null && !params.get(key).isEmpty())
                    .map(key -> {
                        try {
                            // 使用UTF-8编码进行签名（即使charset是其他值）
                            String value = params.get(key);
                            return key + "=" + value;
                        } catch (Exception e) {
                            return key + "=" + params.get(key);
                        }
                    })
                    .collect(Collectors.joining("&"));

            log.debug("待签名字符串: {}", signContent);

            // 3. 使用RSA2签名
            Signature signature = Signature.getInstance("SHA256WithRSA");
            signature.initSign(getPrivateKey());
            signature.update(signContent.getBytes(StandardCharsets.UTF_8)); // 使用UTF-8编码签名
            byte[] signed = signature.sign();

            // 4. Base64编码
            String sign = Base64.getEncoder().encodeToString(signed);
            log.debug("生成签名: {}", sign);

            return sign;

        } catch (Exception e) {
            log.error("生成支付宝签名异常", e);
            throw new BusinessException("ALIPAY_SIGN_ERROR", "生成签名失败: " + e.getMessage());
        }
    }

    /**
     * 构建基础参数 - 确保charset正确
     */
    private Map<String, String> buildBaseParams() {
        Map<String, String> params = new HashMap<>();
        params.put("app_id", appId);
        params.put("charset", "UTF-8"); // 明确指定UTF-8
        params.put("sign_type", "RSA2");
        params.put("timestamp", getCurrentTimestamp());
        params.put("version", "1.0");
        params.put("format", "json");
        return params;
    }


    /**
     * 获取当前时间戳
     */
    private String getCurrentTimestamp() {
        return java.time.LocalDateTime.now().format(
                java.time.format.DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")
        );
    }


    /**
     * 获取私钥
     */
    private PrivateKey getPrivateKey() {
        try {
            String privateKeyContent = privateKey
                    .replace("-----BEGIN PRIVATE KEY-----", "")
                    .replace("-----END PRIVATE KEY-----", "")
                    .replaceAll("\\s", "");

            byte[] keyBytes = Base64.getDecoder().decode(privateKeyContent);
            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            return keyFactory.generatePrivate(keySpec);
        } catch (Exception e) {
            throw new BusinessException("ALIPAY_KEY_ERROR", "加载私钥失败: " + e.getMessage());
        }
    }

    /**
     * 调用支付宝API
     */
    private String callAlipayApi(Map<String, String> params) {
        try {
            // 构建表单数据
            String formData = params.entrySet().stream()
                    .map(entry -> {
                        try {
                            return entry.getKey() + "=" + URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8.name());
                        } catch (Exception e) {
                            return entry.getKey() + "=" + entry.getValue();
                        }
                    })
                    .collect(Collectors.joining("&"));

            log.debug("支付宝API请求表单数据: {}", formData);

            // 设置请求头
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
            headers.add("User-Agent", "Alipay Client");

            HttpEntity<String> request = new HttpEntity<>(formData, headers);

            // 调用接口
            ResponseEntity<String> response = restTemplate.postForEntity(gateway, request, String.class);
            return response.getBody();

        } catch (Exception e) {
            log.error("调用支付宝API异常", e);
            throw new BusinessException("ALIPAY_API_ERROR", "调用支付宝API异常: " + e.getMessage());
        }
    }

    /**
     * 验证支付宝响应签名（简化版，实际需要完整实现）
     */
    private boolean verifySign(Map<String, Object> responseMap) {
        try {
            // 这里需要实现完整的支付宝响应签名验证
            // 包括提取sign、排序参数、使用支付宝公钥验证等
            // 生产环境必须实现此方法

            log.warn("支付宝响应签名验证需要完整实现");
            return true; // 测试环境暂时返回true

        } catch (Exception e) {
            log.error("验证支付宝签名异常", e);
            return false;
        }
    }

    /**
     * 验证手机号格式
     */
    public boolean validatePhoneNumber(String phoneNumber) {
        if (phoneNumber == null || phoneNumber.trim().isEmpty()) {
            return false;
        }
        // 简单的手机号格式验证
        return phoneNumber.matches("^1[3-9]\\d{9}$");
    }

    /**
     * 获取支付宝用户ID (如果需要)
     */
    public String getAlipayUserId(String authCode) {
        try {
            String openId = getOpenId(authCode);

            // 在实际业务中，你可能需要根据手机号关联用户ID
            // 这里返回手机号作为示例，实际应该返回支付宝用户ID
            return openId;

        } catch (Exception e) {
            log.error("获取支付宝用户ID异常", e);
            throw new BusinessException("ALIPAY_USER_ID_ERROR", "获取支付宝用户ID异常: " + e.getMessage());
        }
    }
}
