package com.ylx.web.controller.massage;

import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.ContentType;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.binarywang.wxpay.bean.notify.SignatureHeader;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.ijpay.core.IJPayHttpResponse;
import com.ijpay.core.enums.RequestMethodEnum;
import com.ijpay.core.kit.HttpKit;
import com.ijpay.core.kit.PayKit;
import com.ijpay.core.kit.WxPayKit;
import com.ijpay.wxpay.WxPayApi;
import com.ijpay.wxpay.enums.WxDomainEnum;
import com.ijpay.wxpay.enums.v3.TransferApiEnum;
import com.ijpay.wxpay.model.v3.BatchTransferModel;
import com.ijpay.wxpay.model.v3.TransferDetailInput;
import com.ylx.common.config.WxPayConfig;
import com.ylx.common.core.domain.R;
import com.ylx.common.weixinPay.enums.WxPayTypeEnum;
import com.ylx.giftCard.domain.GiftCardOrder;
import com.ylx.giftCard.enums.GiftCardOrderStatusEnum;
import com.ylx.giftCard.service.IGiftCardOrderService;
import com.ylx.massage.domain.TRecharge;
import com.ylx.massage.domain.TWxUser;
import com.ylx.massage.enums.BillTypeEnum;
import com.ylx.massage.service.RefundVoucherService;
import com.ylx.massage.service.TRechargeService;
import com.ylx.massage.service.TWxUserService;
import com.ylx.order.domain.TOrder;
import com.ylx.order.enums.OrderStatusEnum;
import com.ylx.order.service.TOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import static com.ylx.common.constant.HttpStatus.SUCCESS;

/**
 * @author jianlong
 * @date 2024-04-03 15:27
 */

@RestController
@Slf4j
@RequestMapping("/wx/pay")
@Api(tags = {"微信支付"})
public class PayController {

    @Resource
    private WxPayConfig wxPayProperties;
    @Resource
    private TRechargeService rechargeService;
    @Resource
    private RefundVoucherService refundVoucherService;
    @Resource
    private TWxUserService wxUserService;
    String serialNo;
    @Resource
    private WxPayService wxPayService;
    @Resource
    private IGiftCardOrderService giftCardOrderService;
    @Resource
    private TOrderService orderService;

    /**
     * 小程序微信支付的第一步,统一下单
     */
    @PostMapping("/pay")
    @ApiOperation("AIPV3微信支付充值")
    public R createUnifiedOrder(@RequestBody TRecharge recharge) throws Exception {
        TRecharge rechargeResp = rechargeService.recharge(recharge);
        return rechargeService.getPay(rechargeResp.getRechargeNo(), recharge.getdMoney(), recharge.getcOpenId(), BillTypeEnum.RECHARGE.getInfo(), BillTypeEnum.RECHARGE.getCode().toString());
    }

    /**
     * 获取商户API证书序列号
     *
     * @return String 证书序列号
     */
    private String getSerialNumber() {
        if (StrUtil.isEmpty(serialNo)) {
            // 获取证书序列号
            X509Certificate certificate = PayKit.getCertificate(wxPayProperties.getCertPath());
            if (null != certificate) {
                serialNo = certificate.getSerialNumber().toString(16).toUpperCase();
                // 提前两天检查证书是否有效
                boolean isValid = PayKit.checkCertificateIsValid(certificate, wxPayProperties.getMchId(), -2);
                log.info("证书是否可用 {} 证书有效期为 {}", isValid, DateUtil.format(certificate.getNotAfter(), DatePattern.NORM_DATETIME_PATTERN));
            }
        }
        System.out.println("serialNo:" + serialNo);
        return serialNo;
    }

//    /**
//     * 微信支付回调接口
//     *
//     * @param request
//     * @param response
//     */
//    @RequestMapping(value = "/payNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
//    @ResponseBody
//    @ApiOperation("微信支付回调接口")
//    public void payNotify(HttpServletRequest request, HttpServletResponse response) {
//        log.info("微信支付回调接口====================================>>>>微信支付回调接口");
//        Map<String, String> map = new HashMap<>(12);
//        try {
//            String timestamp = request.getHeader("Wechatpay-Timestamp");
//            String nonce = request.getHeader("Wechatpay-Nonce");
//            String serialNo = request.getHeader("Wechatpay-Serial");
//            String signature = request.getHeader("Wechatpay-Signature");
//
//            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
//            String result = HttpKit.readData(request);
//            log.info("支付通知密文 {}", result);
//
//            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
//            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
//                    wxPayProperties.getMchKey(), wxPayProperties.getPlatFormPath());
//
//            log.info("支付通知明文 {}", plainText);
//
//            if (StrUtil.isNotEmpty(plainText)) {
//                response.setStatus(200);
//                map.put("code", "SUCCESS");
//                map.put("message", "SUCCESS");
//                // 处理业务逻辑
//                JSONObject jsonObject = new JSONObject(plainText);
//                if (jsonObject.get("attach").equals(BillTypeEnum.WX_PAY.getCode().toString())) {
//                    // 服务订单支付成功
//                    orderService.payNotifyOrder(jsonObject.get("out_trade_no").toString());
//                } else if (jsonObject.get("attach").equals(PayTypeEnum.WX_PAY.getCode().toString())) {
//                    // 商品订单支付成功
//                    String productOrderNo = jsonObject.get("out_trade_no").toString();
//                    log.info("商品订单支付回调开始处理，订单号：{}", productOrderNo);
//                    productOrderInfoService.handleWxPayCallback(productOrderNo);
//                    log.info("商品订单支付回调处理完成，订单号：{}", productOrderNo);
//                } else {
//                    TRecharge outTradeNo = rechargeService.increaseAmount(jsonObject.get("out_trade_no").toString());
//                }
//            } else {
//                response.setStatus(500);
//                map.put("code", "ERROR");
//                map.put("message", "签名错误");
//            }
//            response.setHeader("Content-type", ContentType.JSON.toString());
//            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
//            response.flushBuffer();
//        } catch (Exception e) {
//            log.error("系统异常", e);
//        }
//    }

    @PostMapping("/payNotify")
    public Map<String, String> handlePayNotify(@RequestBody String notifyData, @RequestHeader("Wechatpay-Signature") SignatureHeader signature) {

        Map<String, String> resp = new HashMap<>();
        try {
            // 1. SDK验签+解密报文
            WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayService.parseOrderNotifyV3Result(notifyData, signature).getResult();

            String outTradeNo = result.getOutTradeNo();
            String tradeState = result.getTradeState();

            log.info("微信V3回调解密成功，商户订单号：{}，微信单号：{}，交易状态：{}",
                    outTradeNo, result.getTransactionId(), tradeState);

            // 2. 仅SUCCESS才处理订单
            if ("SUCCESS".equals(tradeState)) {

                // 2. 获取我们在下单时传入的 attach
                String attach = result.getAttach();
                String openid = result.getPayer().getOpenid();

                if (StrUtil.isEmpty(openid)) {
                    log.error("openid不存在");
                    resp.put("code", "FAIL");
                    resp.put("message", "openid不存在");
                    return resp;
                }

                log.info("支付成功用户openId，openId: {}", openid);

                TWxUser wxUser = wxUserService.getByOpenId(openid);
                if (ObjectUtil.isNull(wxUser)) {
                    log.error("支付成功用户不存在，openId: {}", openid);
                    resp.put("code", "FAIL");
                    resp.put("message", "支付成功用户不存在");
                    return resp;
                }

                // 3. 根据 attach 判断商品类型并进行不同的业务处理
                if (WxPayTypeEnum.GIFT_CARD.getCode().equals(attach)) {
                    log.info("检测到购物卡支付成功，订单号: {}", outTradeNo);

                    // 3.1 更新订单支付状态
                    LambdaQueryWrapper<GiftCardOrder> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(GiftCardOrder::getOrderNo, outTradeNo);
                    GiftCardOrder cardOrder = this.giftCardOrderService.getOne(wrapper);
                    if (ObjectUtil.isNull(cardOrder)) {
                        log.error("订单不存在，订单号: {}", outTradeNo);
                        resp.put("code", "FAIL");
                        resp.put("message", "订单不存在");
                        return resp;
                    }
                    // 3.2 检查是否已处理
                    if (ObjectUtil.equals(GiftCardOrderStatusEnum.PAID.getCode(), cardOrder.getStatus())) {
                        log.warn("订单已处理过：{}", outTradeNo);
                        resp.put("code", "SUCCESS");
                        resp.put("message", "OK");
                        return resp;
                    }

                    // 3.3 处理订单相关数据
                    this.giftCardOrderService.processGiftCardPayment(result, wxUser, cardOrder);
                } else if (WxPayTypeEnum.EMOTION_GOODS.getCode().equals(attach)) {
                    log.info("检测到情感服务商品支付成功，订单号: {}", outTradeNo);

                    // 3.1 更新订单支付状态
                    LambdaQueryWrapper<TOrder> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(TOrder::getOrderNo, outTradeNo);
                    TOrder order = this.orderService.getOne(wrapper);
                    if (ObjectUtil.isNull(order)) {
                        log.error("订单不存在，订单号: {}", outTradeNo);
                        resp.put("code", "FAIL");
                        resp.put("message", "订单不存在");
                        return resp;
                    }
                    // 3.2 检查是否已处理
                    if (ObjectUtil.equals(OrderStatusEnum.PENDING_DISPATCH.getCode(), order.getStatus())) {
                        log.warn("订单已处理过：{}", outTradeNo);
                        resp.put("code", "SUCCESS");
                        resp.put("message", "OK");
                        return resp;
                    }

                    // 3.3 处理订单相关数据
                    this.orderService.processOrderPayment(result, wxUser, order);

                }
            }

            //3. 返回成功
            resp.put("code", "SUCCESS");
            resp.put("message", "OK");
        } catch (WxPayException e) {
            log.error("微信支付回调异常:{}", e.getMessage(), e);
            resp.put("code", "FAIL");
            resp.put("message", e.getMessage());
        } catch (Exception e) {
            log.error("支付回调处理异常:{}", e.getMessage(), e);
            resp.put("code", "FAIL");
            resp.put("message", "系统异常");
        }
        return resp;
    }

    /**
     * 微信批量提现
     *
     * @param openId
     * @return String
     */
    @RequestMapping("/batchTransfer")
    @ApiOperation("微信批量提现")
    @ResponseBody
    public String batchTransfer(@RequestParam(value = "openId", required = false, defaultValue = "o-_-itxuXeGW3O1cxJ7FXNmq8Wf8") String openId) {
        try {
            BatchTransferModel batchTransferModel = new BatchTransferModel()
                    .setAppid(wxPayProperties.getAppId())
                    .setOut_batch_no(PayKit.generateStr())
                    .setBatch_name("IJPay 测试微信转账到零钱")
                    .setBatch_remark("IJPay 测试微信转账到零钱")
                    .setTotal_amount(1)
                    .setTotal_num(1)
                    .setTransfer_detail_list(Collections.singletonList(
                            new TransferDetailInput()
                                    .setOut_detail_no(PayKit.generateStr())
                                    .setTransfer_amount(1)
                                    .setTransfer_remark("IJPay 测试微信转账到零钱")
                                    .setOpenid(openId)));

            log.info("发起商家转账请求参数 {}", JSONUtil.toJsonStr(batchTransferModel));
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.POST,
                    WxDomainEnum.CHINA.toString(),
                    TransferApiEnum.TRANSFER_BATCHES.toString(),
                    wxPayProperties.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayProperties.getCertKeyPath(),
                    JSONUtil.toJsonStr(batchTransferModel)
            );
            log.info("发起商家转账响应 {}", response);
            // 根据证书序列号查询对应的证书来验证签名结果
            boolean verifySignature = WxPayKit.verifySignature(response, wxPayProperties.getPlatFormPath());
            log.info("verifySignature: {}", verifySignature);
            if (response.getStatus() == SUCCESS && verifySignature) {
                return response.getBody();
            }
            return JSONUtil.toJsonStr(response);
        } catch (Exception e) {
            log.error("系统异常", e);
            return e.getMessage();
        }
    }

    /**
     * 退款
     *
     * @param outRefundNo   退款订单号
     * @param amount        退款金额
     * @param transactionId 微信支付订单号
     * @param outTradeNo    商户订单号
     * @return String 退款结果
     */
    @RequestMapping("/refund")
    @ResponseBody
    public String refund(@RequestParam(required = false) String outRefundNo, @RequestParam(required = false) BigDecimal amount, @RequestParam(required = false) String transactionId, @RequestParam(required = false) String outTradeNo) {
        try {
            return rechargeService.refund(outRefundNo, transactionId, outTradeNo, amount);
        } catch (Exception e) {
            log.error("退款异常", e);
            throw new RuntimeException(e);
        }
    }

    /**
     * 微信退款回调接口
     *
     * @param request
     * @param response
     */
    @ApiOperation("微信退款回调接口")
    @RequestMapping(value = "/refundNotify", method = {org.springframework.web.bind.annotation.RequestMethod.POST, org.springframework.web.bind.annotation.RequestMethod.GET})
    public void refundWechatCallback(HttpServletRequest request, HttpServletResponse response) {
        log.info("微信退款回调接口====================================>>>>微信退款回调接口");
        Map<String, String> map = new HashMap<>(12);
        try {
            String timestamp = request.getHeader("Wechatpay-Timestamp");
            String nonce = request.getHeader("Wechatpay-Nonce");
            String serialNo = request.getHeader("Wechatpay-Serial");
            String signature = request.getHeader("Wechatpay-Signature");

            log.info("timestamp:{} nonce:{} serialNo:{} signature:{}", timestamp, nonce, serialNo, signature);
            String result = HttpKit.readData(request);
            log.info("退款通知密文 {}", result);

            // 需要通过证书序列号查找对应的证书，verifyNotify 中有验证证书的序列号
            String plainText = WxPayKit.verifyNotify(serialNo, result, signature, nonce, timestamp,
                    wxPayProperties.getMchKey(), wxPayProperties.getPlatFormPath());

            log.info("退款通知明文 {}", plainText);

            if (StrUtil.isNotEmpty(plainText)) {
                response.setStatus(200);
                map.put("code", "SUCCESS");
                map.put("message", "SUCCESS");
                // 处理业务逻辑
                JSONObject jsonObject = new JSONObject(plainText);
                //退款单号
                String refundNo = jsonObject.get("out_refund_no").toString();
                refundVoucherService.refundWechatCallback(refundNo);
            } else {
                response.setStatus(500);
                map.put("code", "ERROR");
                map.put("message", "签名错误");
            }
            response.setHeader("Content-type", ContentType.JSON.toString());
            response.getOutputStream().write(JSONUtil.toJsonStr(map).getBytes(StandardCharsets.UTF_8));
            response.flushBuffer();
        } catch (Exception e) {
            log.error("系统异常", e);
        }
    }


    /**
     * 根据商户订单号查询微信支付订单
     *
     * @param outTradeNo 商户订单号
     * @return R 订单详情
     */
    @GetMapping("/query/order/{outTradeNo}")
    @ApiOperation("根据商户订单号查询微信支付订单")
    public R queryOrderByOutTradeNo(@PathVariable("outTradeNo") String outTradeNo) {
        try {
            log.info("查询微信支付订单，商户订单号：{}", outTradeNo);

            // V3 API：根据商户订单号查询订单接口路径
            // GET /v3/pay/transactions/out-trade-no/{out_trade_no}
            String queryUrl = String.format("/v3/pay/transactions/out-trade-no/%s", outTradeNo);
            log.info("查询订单URL：{}", queryUrl);
            Map<String, String> queryParams = new HashMap<>();
            queryParams.put("mchid", wxPayProperties.getMchId());
            // 调用微信支付V3接口查询订单
            IJPayHttpResponse response = WxPayApi.v3(
                    RequestMethodEnum.GET,
                    WxDomainEnum.CHINA.toString(),
                    queryUrl,
                    wxPayProperties.getMchId(),
                    getSerialNumber(),
                    null,
                    wxPayProperties.getCertKeyPath(),
                    queryParams
            );
            log.info("查询订单响应状态：{}，响应体：{}", response.getStatus(), response.getBody());
            // 处理响应
            if (response.getStatus() == SUCCESS) {
                // 验证响应签名
                boolean verifySignature = WxPayKit.verifySignature(response, wxPayProperties.getPlatFormPath());
                log.info("响应签名验证结果：{}", verifySignature);

                if (verifySignature) {
                    log.info("商户订单号 {} 查询成功，订单信息：{}", outTradeNo, response.getBody());
                    JSONObject result = JSONUtil.parseObj(response.getBody());
                    return R.ok(result);
                } else {
                    log.error("商户订单号 {} 查询响应签名验证失败", outTradeNo);
                    return R.fail("查询订单响应签名验证失败");
                }
            } else {
                log.error("商户订单号 {} 查询失败，状态码：{}，响应：{}", outTradeNo, response.getStatus(), response.getBody());
                return R.fail("查询订单失败：" + response.getBody());
            }
        } catch (Exception e) {
            log.error("查询微信支付订单异常，商户订单号：{}，错误：{}", outTradeNo, e.getMessage(), e);
            return R.fail("查询订单异常：" + e.getMessage());
        }
    }

}
