package com.openhis.web.externalintegration.appservice.impl;

import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSON;
import com.core.common.core.domain.R;
import com.core.common.enums.TenantOptionDict;
import com.core.web.util.TenantOptionUtil;
import com.openhis.web.externalintegration.appservice.IBankPosCloudAppService;
import com.openhis.web.externalintegration.dto.BpcTransactionRequestDto;
import com.openhis.web.externalintegration.dto.BpcTransactionResponseDto;
import com.openhis.web.externalintegration.enums.BpcPayType;
import com.openhis.web.externalintegration.enums.BpcTranType;
import com.openhis.web.externalintegration.utils.BpcHttpUtil;
import com.openhis.web.externalintegration.utils.BpcTraceNoGenerator;

import lombok.extern.slf4j.Slf4j;

/**
 * BPC商户接口Service业务层处理
 *
 * @author Thanking
 * @date 2025-10-16
 */
@Slf4j
@Service
public class BankPosCloudAppServiceImpl implements IBankPosCloudAppService {

    /**
     * 被扫消费
     *
     * @param txnAmt 交易金额
     * @param merTradeNo 商户系统订单号
     * @param scanCode 二维码信息
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> processConsumerScan(String txnAmt, String merTradeNo, String scanCode, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(txnAmt)) {
            return R.fail("交易金额不能为空");
        }
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        if (StringUtils.isEmpty(scanCode)) {
            return R.fail("二维码信息不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，被扫消费
            .setTranType(BpcTranType.C.getValue())
            // 交易金额
            .setTxnAmt(txnAmt)
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 二维码信息
            .setScanCode(scanCode)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC被扫消费】，交易金额：{}，商户系统订单号：{}，二维码信息：{}，设备终端编号：{}", txnAmt, merTradeNo, scanCode, posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 主扫下单
     *
     * @param txnAmt 交易金额
     * @param merTradeNo 商户系统订单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> createMerchantScanOrder(String txnAmt, String merTradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(txnAmt)) {
            return R.fail("交易金额不能为空");
        }
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，主扫下单
            .setTranType(BpcTranType.F.getValue())
            // 交易金额
            .setTxnAmt(txnAmt)
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC主扫下单】，交易金额：{}，商户系统订单号：{}，设备终端编号：{}", txnAmt, merTradeNo, posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 消费订单查询
     *
     * @param merTradeNo 商户系统订单号
     * @param tradeNo 原交易订单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> queryPaymentOrder(String merTradeNo, String tradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        // if (StringUtils.isEmpty(tradeNo)) {
        // return R.fail("原交易订单号不能为空");
        // }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，支付结果查询
            .setTranType(BpcTranType.G.getValue())
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 原交易订单号
            .setTradeNo(tradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC消费订单查询】，商户系统订单号：{}，原交易订单号：{}，设备终端编号：{}", merTradeNo, tradeNo, posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 关闭订单
     *
     * @param merTradeNo 商户系统订单号
     * @param tradeNo 原交易订单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> closeOrder(String merTradeNo, String tradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        if (StringUtils.isEmpty(tradeNo)) {
            return R.fail("原交易订单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，关闭订单
            .setTranType(BpcTranType.S.getValue())
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 原交易订单号
            .setTradeNo(tradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC关闭订单】，商户系统订单号：{}，原交易订单号：{}，设备终端编号：{}", merTradeNo, tradeNo, posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 申请退货
     *
     * @param txnAmt 交易金额
     * @param vfTradeNo 退款退订定金单号
     * @param merTradeNo 商户系统订单号
     * @param tradeNo 原交易订单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> applyForRefund(String txnAmt, String vfTradeNo, String merTradeNo, String tradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(txnAmt)) {
            return R.fail("交易金额不能为空");
        }
        if (StringUtils.isEmpty(vfTradeNo)) {
            return R.fail("退款退订定金单号不能为空");
        }
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        if (StringUtils.isEmpty(tradeNo)) {
            return R.fail("原交易订单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，退货
            .setTranType(BpcTranType.R.getValue())
            // 交易金额
            .setTxnAmt(txnAmt)
            // 退款退订定金单号
            .setVfTradeNo(vfTradeNo)
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 原交易订单号
            .setTradeNo(tradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC申请退货】，交易金额：{}，退款退订定金单号：{}，商户系统订单号：{}，原交易订单号：{}，设备终端编号：{}", txnAmt, vfTradeNo, merTradeNo, tradeNo,
            posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 查询退货订单
     *
     * @param vfTradeNo 退款退订定金单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> queryRefundOrder(String vfTradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(vfTradeNo)) {
            return R.fail("退款退订定金单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，退款结果查询
            .setTranType(BpcTranType.J.getValue())
            // 退款退订定金单号
            .setVfTradeNo(vfTradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC查询退货订单】，退款退订定金单号：{}", vfTradeNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 消费撤销
     *
     * @param txnAmt 交易金额
     * @param vfTradeNo 退款退订定金单号
     * @param merTradeNo 商户系统订单号
     * @param tradeNo 原交易订单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> reversePayment(String txnAmt, String vfTradeNo, String merTradeNo, String tradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(txnAmt)) {
            return R.fail("交易金额不能为空");
        }
        if (StringUtils.isEmpty(vfTradeNo)) {
            return R.fail("退款退订定金单号不能为空");
        }
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        if (StringUtils.isEmpty(tradeNo)) {
            return R.fail("原交易订单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，消费撤销
            .setTranType(BpcTranType.D.getValue())
            // 交易金额
            .setTxnAmt(txnAmt)
            // 退款退订定金单号
            .setVfTradeNo(vfTradeNo)
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 原交易订单号
            .setTradeNo(tradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC消费撤销】，交易金额：{}，退款退订定金单号：{}，商户系统订单号：{}，原交易订单号：{}，设备终端编号：{}", txnAmt, vfTradeNo, merTradeNo, tradeNo,
            posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 查询撤销订单
     *
     * @param merTradeNo 商户系统订单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> queryReversalOrder(String merTradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(merTradeNo)) {
            return R.fail("商户系统订单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，撤销结果查询
            .setTranType(BpcTranType.Z.getValue())
            // 商户系统订单号
            .setMerTradeNo(merTradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC查询撤销订单】，商户系统订单号：{}，设备终端编号：{}", merTradeNo, posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 银行卡退货功能
     *
     * @param txnAmt 交易金额
     * @param pan 银行卡号
     * @param vfTradeNo 退款退订定金单号
     * @param posNo 设备终端编号
     * @return 结果
     */
    @Override
    public R<?> processCardRefund(String txnAmt, String pan, String vfTradeNo, String posNo) {
        // 参数验证
        if (StringUtils.isEmpty(txnAmt)) {
            return R.fail("交易金额不能为空");
        }
        if (StringUtils.isEmpty(pan)) {
            return R.fail("银行卡号不能为空");
        }
        if (StringUtils.isEmpty(vfTradeNo)) {
            return R.fail("退款退订定金单号不能为空");
        }
        if (StringUtils.isEmpty(posNo)) {
            return R.fail("设备终端编号不能为空");
        }
        // 作成请求参数
        BpcTransactionRequestDto requestDto = new BpcTransactionRequestDto()
            // 交易类型，退货
            .setTranType(BpcTranType.R.getValue())
            // 交易金额
            .setTxnAmt(txnAmt)
            // 终端流水号
            .setPayType(BpcPayType.BANK_CARD.getValue())
            // 银行卡号
            .setPan(pan)
            // 退款退订定金单号
            .setVfTradeNo(vfTradeNo)
            // 设备终端编号
            .setPosNo(posNo);
        log.info("【BPC银行卡退货功能】，交易金额：{}，银行卡号：{}，退款退订定金单号：{}，设备终端编号：{}", txnAmt, pan, vfTradeNo, posNo);
        // 发起交易请求
        return submitTransactionRequest(requestDto);
    }

    /**
     * 发送交易请求
     *
     * @param requestDto 请求参数
     * @return 结果
     */
    private R<?> submitTransactionRequest(BpcTransactionRequestDto requestDto) {
        // 验证租户配置
        String mid = TenantOptionUtil.getOptionContent(TenantOptionDict.BPC_MID);
        if (StringUtils.isEmpty(mid)) {
            return R.fail("BPC商户号未配置");
        }
        String tid = TenantOptionUtil.getOptionContent(TenantOptionDict.BPC_TID);
        if (StringUtils.isEmpty(tid)) {
            return R.fail("BPC终端号未配置");
        }
        String md5SharedSecret = TenantOptionUtil.getOptionContent(TenantOptionDict.BPC_MD5_SHARED_SECRET);
        if (StringUtils.isEmpty(md5SharedSecret)) {
            return R.fail("BPCMD5签名密钥未配置");
        }
        String requestUrl = TenantOptionUtil.getOptionContent(TenantOptionDict.BPC_REQUEST_URL);
        if (StringUtils.isEmpty(requestUrl)) {
            return R.fail("BPC请求URL未配置");
        }
        // 生成终端流水号
        String traceNo = BpcTraceNoGenerator.nextTraceNo();
        // 设置请求终端流水号
        requestDto.setTraceNo(traceNo);
        // 设置其他固定参数
        requestDto.setMid(mid).setTid(tid);
        // 将参数转化为json字符串
        String jsonStr = JSON.toJSONString(requestDto);
        log.info("【BPC请求报文】：{}", jsonStr);
        // 发起post请求
        String postResponse;
        try {
            postResponse = BpcHttpUtil.httpPost(jsonStr, md5SharedSecret, requestUrl);
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
        log.info("【BPC响应报文】：{}", postResponse);
        // 解析响应报文
        BpcTransactionResponseDto responseDto;
        try {
            responseDto = JSON.parseObject(postResponse, BpcTransactionResponseDto.class);
            if (StringUtils.isNotEmpty(responseDto.getTraceNo()) && !traceNo.equals(responseDto.getTraceNo())) {
                return R.fail("终端流水号不一致，交易失败");
            }
        } catch (Exception e) {
            return R.fail("报文解析失败");
        }
        // 返回响应结果
        return R.ok(responseDto);
    }
}