package cn.iocoder.yudao.module.system.controller.admin.pay;

import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.module.system.controller.admin.pay.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.ExpenseOrderDO;
import cn.iocoder.yudao.module.system.dal.dataobject.ccb.MerchantRecordDO;
import cn.iocoder.yudao.module.system.dal.mysql.biz.ExpenseOrderMapper;
import cn.iocoder.yudao.module.system.dal.mysql.ccb.MerchantRecordMapper;
import cn.iocoder.yudao.module.system.enums.ErrorCodeConstants;
import cn.iocoder.yudao.module.system.service.ccb.CcbBusinessService;
import cn.iocoder.yudao.module.system.util.pay.CcbPayConstant;
import cn.iocoder.yudao.module.system.util.pay.CcbPayUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.annotation.security.PermitAll;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.Map;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;

/**
 * 建设银行微信统一下单控制器
 */
@Slf4j
@RestController
@RequestMapping("/pay/ccb-wx")
public class CcbWxUnifiedOrderController {

    @Resource
    private ExpenseOrderMapper expenseOrderMapper;

    @Autowired
    private CcbBusinessService ccbBusinessService;

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private MerchantRecordMapper merchantRecordMapper;

    @PostMapping("/unified-order")
    @PermitAll
    public CommonResult<WxPayParams> unifiedOrder(@RequestBody CcbWxUnifiedOrderRequest req) throws Exception {
        ExpenseOrderDO expenseOrder = expenseOrderMapper.selectById(req.getOrderId());
        if (expenseOrder == null) {
            throw exception(ErrorCodeConstants.COMMON_NOT_FOUND);
        }
        Long tenantId = expenseOrder.getTenantId();
        // 商户信息
        MerchantRecordDO merchantRecordDO = merchantRecordMapper.selectOne(new LambdaQueryWrapperX<MerchantRecordDO>()
                .eq(MerchantRecordDO::getTenantId, tenantId));
        ResponseEntity<String> response = restTemplate.getForEntity(
                "http://home.ynims.com/api/wechat/getOpenIdsByUserPhone?userPhone={userPhone}", String.class, req.getUserPhone());

        log.info("查询用户openId结果：{}", response.getBody());

        ObjectMapper objectMapper = new ObjectMapper();
        JsonNode rootNode = objectMapper.readTree(response.getBody());
        int code = rootNode.path("code").asInt();
        WxPayParams wxPayParams = new WxPayParams();
        if (code == 200) {
            JsonNode dataNode = rootNode.path("data");
            String miniAppId = dataNode.path("miniAppId").asText();
            String miniOpenId = dataNode.path("miniOpenId").asText();

            //        //测试阶段金额设置为0.01
//        amount = new BigDecimal("0.01");

            // 1. 构建请求对象（赋值必传+可选字段，空值默认""）
            CcbPayRequest request = new CcbPayRequest();
//            request.setMerchantId(CcbPayConstant.MERCHANTID);
            request.setMerchantId(merchantRecordDO.getMerchantNumber());
//            request.setPosId(CcbPayConstant.POSID);
            request.setPosId(merchantRecordDO.getCounterNumber());
            request.setBranchId(CcbPayConstant.BRANCHID);
            request.setOrderId(expenseOrder.getBillOrderNumber());
            request.setPayment(req.getAmount());
            request.setTradeType("MINIPRO");
            request.setSubAppId(miniAppId);
            request.setSubOpenId(miniOpenId);
            request.setPub(CcbPayConstant.CCB_PUB);
            request.setRemark1("JTSH:"+CcbPayConstant.MERCHANTID+CcbPayConstant.POSID);
            // 2. 生成MAC值
            request.setMac(CcbPayUtils.generateMac(request));

            // 3. 发送请求并解析响应
            String respStr = CcbPayUtils.sendRequest(request);
            JSONObject jsonObject = JSON.parseObject(respStr);

            // 4. 校验业务结果并发起请求微信参数

            if ("true".equals(jsonObject.getString("SUCCESS"))) {
                String payUrl = jsonObject.getString("PAYURL");
                try {
                    wxPayParams = CcbPayUtils.requestPayUrl(payUrl);
                } catch (Exception e) {
                    log.error("请求微信参数异常 {}", e.getMessage());
                }

            }
        } else {
            // 处理错误情况
            log.error("请求用户openId失败，错误码: {} ", code);
            wxPayParams.setSuccess("true");
            wxPayParams.setErrCode(ErrorCodeConstants.COMMON_NOT_FOUND.getCode().toString());
            wxPayParams.setErrMsg("请求用户openId失败");
        }
        return CommonResult.success(wxPayParams);
    }


    @PostMapping(value = "/callback", consumes = {MediaType.APPLICATION_FORM_URLENCODED_VALUE, MediaType.APPLICATION_JSON_VALUE})
    @PermitAll
    @TenantIgnore
    public void wechatPayCallback(@RequestParam Map<String, String> paramMap, HttpServletResponse response) throws IOException {
        log.info("收到建行微信支付回调，参数：{}", paramMap);
        response.setContentType("text/plain;charset=UTF-8");
        CcbNotifyResp notifyResp;
        String orderId = paramMap.get("ORDERID");
        try {
            String signSource = CcbPayUtils.buildSignSource(paramMap);
            log.info("RSA验签原串：{}", signSource);

            CCBSign.RSASig rsaSignUtil = new CCBSign.RSASig();
            rsaSignUtil.setPublicKey(CcbPayConstant.PUB_KEY);
            String callBackSign = paramMap.get("SIGN");

            //验签（仅用新密钥，核心步骤）
            boolean verifyResult = rsaSignUtil.verifySigature(callBackSign, signSource);
            log.info("订单号{} 验签结果={}，签名原串={}", orderId, verifyResult, signSource);
            if (!verifyResult) {
                throw new Exception("验签失败：订单号=" + orderId);
            }
            // 基础校验和业务处理
            ccbBusinessService.handleOrderBusiness(paramMap);

            // 5. 处理成功：返回SUCCESS（HTTP 200）
            notifyResp = CcbNotifyResp.ok();
            response.setStatus(HttpServletResponse.SC_OK);
        } catch (Exception e) {
            // 6. 处理失败：返回FAIL（非200，建行重发）
            log.error("建行回调处理异常 {},订单号{}", e, orderId);
            notifyResp = CcbNotifyResp.fail(e.getMessage());
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        }

        // 7. 响应结果
        response.getWriter().write(notifyResp.getResp());
    }


    @PostMapping("/closeOrder")
    @PermitAll
    public CommonResult<JSONObject> closeOrder(
            @RequestParam String orderId,
            @RequestParam(required = false) String subAppId) throws Exception {
        // 传回来的就是智慧系统的订单编号
        ExpenseOrderDO expenseOrder = expenseOrderMapper.selectOne(new LambdaQueryWrapperX<ExpenseOrderDO>()
                .eq(ExpenseOrderDO::getBillOrderNumber,orderId));
        MerchantRecordDO merchantRecordDO = merchantRecordMapper.selectOne(new LambdaQueryWrapperX<MerchantRecordDO>()
                .eq(MerchantRecordDO::getTenantId, expenseOrder.getTenantId()));
        CcbCloseOrderRequestVO request = new CcbCloseOrderRequestVO();
//        request.setMERCHANTID(CcbPayConstant.MERCHANTID);
//        request.setPOSID(CcbPayConstant.POSID);
        request.setMERCHANTID(merchantRecordDO.getMerchantNumber());
        request.setPOSID(merchantRecordDO.getCounterNumber());
        request.setBRANCHID(CcbPayConstant.BRANCHID);
        request.setORDERID(orderId);
        request.setSUB_APPID(subAppId); // 可选字段，可为null


        String mac = CcbPayUtils.generateCloseOrderMac(request);
        request.setMAC(mac);
        log.info("关闭订单生成MAC：{}，订单号：{}", mac, orderId);


        String responseStr = CcbPayUtils.sendCloseOrderRequest(request);
        JSONObject response = JSONObject.parseObject(responseStr);

        // 7. 业务结果日志（ERRCODE=000000表示关闭成功）
        if ("000000".equals(response.get("ERRCODE"))) {
            log.info("订单关闭成功，订单号：{}，响应信息：{}", orderId, response.get("ERRMSG"));
        } else {
            log.error("订单关闭失败，订单号：{}，错误码：{}，错误信息：{}", orderId, response.get("ERRCODE"), response.get("ERRMSG"));
            // 可根据业务需求抛出异常，或返回失败响应
            throw new Exception(String.format("订单关闭失败：错误码[%s]，错误信息[%s]", response.get("ERRCODE"), response.get("ERRMSG")));
        }
        return CommonResult.success(response);
    }
}
