package com.heyu.api.controller.vv;


import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.heyu.api.common.annotation.Describe;
import com.heyu.api.data.dao.vv.VvTradeOrderDao;
import com.heyu.api.data.dao.vv.VvTradeOrderLineDao;
import com.heyu.api.data.entity.vv.VvTradeOrderEntity;
import com.heyu.api.data.entity.vv.VvTradeOrderLineEntity;
import com.heyu.api.data.enums.OrderStatusEnums;
import com.heyu.api.jsapi.JsapiPrepay;
import com.heyu.api.jsapi.dto.pay.DirectAPIv3QueryResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.crypto.Cipher;
import javax.crypto.spec.GCMParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import java.util.Base64;
import java.util.Date;
import java.util.List;

/**
 * 微信支付回调通知控制器
 * <p>
 * 用于处理微信支付的异步通知回调，接收微信支付平台发送的支付结果通知，
 * 并根据通知内容更新订单状态。
 * </p>
 *
 * @author heyu
 * @since 1.0
 */
@Slf4j
@RestController
@RequestMapping("/app/weixin")
public class AppWeiXinPayNotifyController {

    /**
     * 交易订单明细数据访问对象
     */
    @Autowired
    private VvTradeOrderLineDao vvTradeOrderLineDao;

    /**
     * 微信支付APIv3密钥，用于解密回调通知中的加密数据
     */
    @Value("${eb.config.weixin.pay.apiv3key}")
    private String apiv3key;

    /**
     * 交易订单数据访问对象
     */
    @Autowired
    private VvTradeOrderDao tradeOrderDao;

    /**
     * 微信支付商户号
     */
    @Value("${eb.config.weixin.pay.mchid}")
    private String mchid;

    /**
     * JSAPI预支付服务
     */
    @Autowired
    private  JsapiPrepay jsapiPrepay;

    /**
     * 处理微信支付回调通知
     * <p>
     * 接收微信支付平台发送的异步通知，解密通知内容，验证支付结果，并更新订单状态。
     * </p>
     *
     * <p>处理流程：</p>
     * <ol>
     *   <li>解析微信支付回调通知的JSON数据</li>
     *   <li>提取加密字段（ciphertext、associated_data、nonce）</li>
     *   <li>使用AES-GCM算法解密数据</li>
     *   <li>解析解密后的支付结果数据</li>
     *   <li>如果支付成功，更新商户订单状态</li>
     *   <li>返回处理结果给微信支付平台</li>
     * </ol>
     *
     * @param requestBody 微信支付回调通知的原始JSON数据
     * @return 处理结果的JSON字符串，成功返回 {"code":"SUCCESS","message":"OK"}，失败返回 {"code":"FAIL","message":"Server Error"}
     */
    @Describe("微信支付回调")
    @PostMapping("/payNotify")
    public String handleWeChatPayCallback(@RequestBody String requestBody) {
        try {
            // Step 1: 解析微信支付回调通知的JSON
            ObjectMapper objectMapper = new ObjectMapper();
            JsonNode rootNode = objectMapper.readTree(requestBody);
            // 获取加密数据
            String ciphertext = rootNode.get("resource").get("ciphertext").asText();
            String associatedData = rootNode.get("resource").get("associated_data").asText();
            String nonce = rootNode.get("resource").get("nonce").asText();
            // Step 2: 解密加密数据，使用AES-GCM解密
            String decryptedData = decrypt(ciphertext, associatedData, nonce);
            // Step 3: 处理解密后的数据
            JsonNode resultData = objectMapper.readTree(decryptedData);
            String transactionId = resultData.get("transaction_id").asText(); // 微信支付订单号
            String outTradeNo = resultData.get("out_trade_no").asText();      // 商户订单号
            String tradeState = resultData.get("trade_state").asText();       // 支付状态
            log.info("handleWeChatPayCallback outTradeNo:{},tradeState:{},transactionId:{},decryptedData:{}", outTradeNo, tradeState,transactionId,decryptedData);
            // 根据支付结果处理商户业务逻辑
            if ("SUCCESS".equals(tradeState)) {
                // 支付成功的逻辑，更新订单状态
                updateOrderStatus(outTradeNo, transactionId);
            }
            // Step 4: 返回处理结果，通知微信支付停止回调
            return "{\"code\":\"SUCCESS\",\"message\":\"OK\"}";
        } catch (Exception e) {
            e.printStackTrace();
            // 如果处理失败，返回错误信息
            return "{\"code\":\"FAIL\",\"message\":\"Server Error\"}";
        }
    }

    /**
     * AES-GCM解密方法
     * <p>
     * 使用微信支付APIv3密钥对回调通知中的加密数据进行解密。
     * 采用AES-GCM算法，密钥长度为256位，GCM标签长度为128位。
     * </p>
     *
     * @param ciphertext 加密后的密文（Base64编码）
     * @param associatedData 附加数据，用于GCM认证
     * @param nonce 随机数，用作GCM初始化向量
     * @return 解密后的明文字符串
     * @throws Exception 解密过程中发生的异常
     */
    private String decrypt(String ciphertext, String associatedData, String nonce) throws Exception {
        // 将APIv3密钥转为字节数组
        byte[] key = apiv3key.getBytes(StandardCharsets.UTF_8);
        Key secretKey = new SecretKeySpec(key, "AES");

        // 使用AES-GCM解密
        Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
        GCMParameterSpec spec = new GCMParameterSpec(128, nonce.getBytes(StandardCharsets.UTF_8));
        cipher.init(Cipher.DECRYPT_MODE, secretKey, spec);
        cipher.updateAAD(associatedData.getBytes(StandardCharsets.UTF_8));
        byte[] decodedCiphertext = Base64.getDecoder().decode(ciphertext);
        byte[] decryptedData = cipher.doFinal(decodedCiphertext);

        return new String(decryptedData, StandardCharsets.UTF_8);
    }

    /**
     * 更新订单状态
     * <p>
     * 根据微信支付回调通知的结果，更新商户订单及子订单的支付状态。
     * </p>
     *
     * <p>更新内容：</p>
     * <ul>
     *   <li>查询微信支付订单详情并保存到主订单的交易信息字段</li>
     *   <li>更新主订单的微信支付交易号</li>
     *   <li>将所有子订单的状态更新为"待发货"</li>
     *   <li>记录子订单的支付时间和微信支付交易号</li>
     * </ul>
     *
     * @param outTradeNo 商户订单号
     * @param transactionId 微信支付交易号
     */
    private void updateOrderStatus(String outTradeNo, String transactionId) {
        try {
            DirectAPIv3QueryResponse response = jsapiPrepay.queryOrder(transactionId);
            VvTradeOrderEntity tradeOrderEntity  = tradeOrderDao.selectVvTradeOrderByOutTradeNo(outTradeNo);
            tradeOrderEntity.setTradeInfo(JSON.toJSONString(response));
            tradeOrderEntity.setTransactionId(transactionId);
            tradeOrderDao.updateVvTradeOrderById(tradeOrderEntity);

            // 这里是更新商户订单状态的逻辑，例如标记订单已支付
            log.info("handleWeChatPayCallback 订单 " + outTradeNo + " 已支付，交易号：" + transactionId + "开始更新子订单信息");
            List<VvTradeOrderLineEntity> vvTradeOrderLineEntityList = vvTradeOrderLineDao.selectVvTradeOrderLineByTradeOrderId(tradeOrderEntity.getId());
            for (VvTradeOrderLineEntity vvTradeOrderLineEntity : vvTradeOrderLineEntityList) {
                vvTradeOrderLineEntity.setStatus(OrderStatusEnums.wait_shipping.getStatus());
                vvTradeOrderLineEntity.setGmtPay(new Date());
                vvTradeOrderLineEntity.setTransactionId(transactionId);
                vvTradeOrderLineDao.updateVvTradeOrderLineById(vvTradeOrderLineEntity);
            }
        }catch ( Exception e ){
            log.error("AppWeiXinPayNotifyController updateOrderStatus error:{}",e.getMessage());
        }

    }

}
