package com.clx.performance.service.impl.thirdparty.nbbank;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.clx.performance.config.nbbank.NbBankConfig;
import com.clx.performance.dao.nbbank.NbBankRecordDao;
import com.clx.performance.enums.PerformanceResultEnum;
import com.clx.performance.enums.nbbank.NbBankRecordEnum;
import com.clx.performance.model.nbbank.NbBankRecord;
import com.clx.performance.service.thirdparty.nbbank.NbBankThirdpartyService;
import com.clx.performance.utils.LocalDateTimeUtils;
import com.msl.common.exception.ServiceSystemException;
import com.nbopen.api.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Objects;

/**
 * 易付通
 */
@Slf4j
@Service
public class NbBankThirdpartyServiceImpl implements NbBankThirdpartyService {

    @Autowired
    private NbBankConfig nbBankConfig;

    @Autowired
    private NbBankRecordDao nbBankRecordDao;

    static {
        ClassPathResource classPathResource = new ClassPathResource("bank/config-nbbank.json");
        InputStream inputStream;
        try {
            inputStream = classPathResource.getInputStream();
            boolean initResult = NBOpenSDK.init(inputStream);
            log.info("NBSDK初始化状态:{}", initResult);
            log.info("sdk版本信息:{}", NBOpenSDK.getVersionInfo());
        } catch (IOException e) {
            e.printStackTrace();
        }

    }


    /**
     * 下单
     * 5.5转账直连下单
     * 商户号：EFT33021200556315
     * 银行转账：86041110000075918（户名：客户客户）
     * 订单支付：结算账号（86041110000075926（户名：客户客户））
     * 响应结果：
     *{
     *     "data": {
     *         "acctNm": "客户客户",
     *         "acctOpenBankNm": "宁波银行股份有限公司",
     *         "bankId": "313332082914",
     *         "cardNo": "86041110000075918",
     *         "errorCode": "000000",
     *         "errorMsg": "成功",
     *         "signNo": "2976409",
     *         "transSeqNo": "20231129142846065496766yDTQtg2",
     *         "virtualDays": "2024-05-26"
     *     },
     *     "head": {
     *         "rqsJrnlNo": "15543427719351510",
     *         "rspCode": "000000",
     *         "rspDate": "2023-11-29",
     *         "rspMsg": "交易成功",
     *         "rspTime": "14:28:49:600"
     *     }
     * }
     *
     * @Param
     * merSeqNo: 商户流水
     * merId: 商户号
     * amount: 订单金额(分)
     */
    @Override
    public JSONObject directBankTransferOrder(String merSeqNo, String merId, Integer amount) {
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("transId", "IP01");           //交易识别码 必填
            jsonObject.put("merId", merId);              //商户号 必填

            jsonObject.put("merSeqNo", merSeqNo);        //商户流水 必填
            jsonObject.put("merDtTm", LocalDateTimeUtils.formatTime());             //商户时间 必填

            jsonObject.put("trxAmt", new BigDecimal(amount).movePointLeft(2));      //订单金额 必填
            jsonObject.put("orderDesc", "运输");          //订单详情 必填
            jsonObject.put("productName", "运费");        //商品名称 必填
            jsonObject.put("productId", "001");          //商品编号 必填
            jsonObject.put("productNum", "1");           //商品数量 必填


//            jsonObject.put("closeDtTm", "2023-11-29 13:39:16");     //关单时间
//            jsonObject.put("mobilePhone", "13000000000");     //手机号

            HashMap<String,String> httpHeader = new HashMap<>();

            RequestApiData requestApiData = new RequestApiData();
            requestApiData.setAppkey(nbBankConfig.getAppKey());
            requestApiData.setData(jsonObject);
            requestApiData.setProductId("YFT");
            requestApiData.setServiceId("directBankTransferOrder");
            requestApiData.setHttpHeader(httpHeader);

            RequestHead requestHead = new RequestHead();
            requestHead.setRqsJrnlNo(NBOpenSDK.getRandom());

            SDKRequest request = new SDKRequest();
            request.setData(requestApiData);
            request.setHead(requestHead);

            log.info("宁波银行, 下单(directBankTransferOrder), 参数: {}", JSON.toJSONString(request));
            SDKResponse response = NBOpenSDK.send(request);
            log.info("宁波银行, 下单(directBankTransferOrder), 结果: {}", JSON.toJSONString(response));

            recordSave(NbBankRecordEnum.Type.DIRECT_BANK_TRANSFER_ORDER.getCode(), request, response);

            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject data = responseJson.getJSONObject("data");

            if (!StringUtils.equals(data.getString("errorCode"), "000000")){
                log.info("宁波银行, 下单失败(directBankTransferOrder), code:{}, msg:{}", data.getString("errorCode"), data.getString("errorMsg"));
                throw new ServiceSystemException(PerformanceResultEnum.NB_BANK_API_ERROR);
            }

            return data;

        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new ServiceSystemException(PerformanceResultEnum.NB_BANK_API_ERROR);
    }

    /**
     * 订单支付收款模式
     * 易付通接口编程-含订单支付
     * 5.13银联订单支付收款模式
     * 商户号：EFT33021200556315
     * 银行转账：86041110000075918（户名：客户客户）
     * 订单支付：结算账号（86041110000075926（户名：客户客户））
     * 86041110000076809:黑玫瑰
     * 响应结果：
     * {
     *     "data": {
     *         "errorCode": "000000",
     *         "errorMsg": "成功",
     *         "frontUrl": "",
     *         "merId": "EFT33021200556315",
     *         "merSeqNo": "20231129133913",
     *         "signData": "",
     *         "transSeqNo": "2023112913391406547689VYvNioNz"
     *     },
     *     "head": {
     *         "rqsJrnlNo": "14414965925389704",
     *         "rspCode": "000000",
     *         "rspDate": "2023-11-29",
     *         "rspMsg": "交易成功",
     *         "rspTime": "13:39:16:035"
     *     }
     * }
     *
     * @Param
     * merSeqNo: 商户流水
     * merId: 商户号
     * amount: 订单金额(分)
     * payAcctOpenBankId: 开户行号
     * payAcctNo: 付款账号
     * payAcctNm: 付款户名
     */
    @Override
    public JSONObject unionPayDirectOrder(String merSeqNo, String merId, Integer amount,
                                          String payAcctOpenBankId, String payAcctNo, String payAcctNm) {
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("transId", "IP01");           //交易识别码 必填
            jsonObject.put("merId", merId);              //商户号 必填

            jsonObject.put("merSeqNo", merSeqNo);        //商户流水 必填
            jsonObject.put("merDtTm", LocalDateTimeUtils.formatTime());            //商户时间 必填

            jsonObject.put("trxAmt", new BigDecimal(amount).movePointLeft(2));     //订单金额 必填
            jsonObject.put("orderDesc", "运输");          //订单详情 必填
            jsonObject.put("productName", "运费");        //商品名称 必填
            jsonObject.put("productId", "001");           //商品编号 必填
            jsonObject.put("productNum", "1");            //商品数量 必填

            jsonObject.put("bankType", "00");                           //账户类型 必填
            jsonObject.put("payAcctOpenBankId", payAcctOpenBankId);     //开户行号 必填
            jsonObject.put("payAcctNo", payAcctNo);                     //付款账号 必填
            jsonObject.put("payAcctNm", payAcctNm);                     //付款户名 必填
//        jsonObject.put("mobilePhone", "13000000000");     //手机号

            HashMap<String,String> httpHeader = new HashMap<>();


            RequestApiData requestApiData = new RequestApiData();
            requestApiData.setAppkey(nbBankConfig.getAppKey());
            requestApiData.setData(jsonObject);
            requestApiData.setProductId("YFT");
            requestApiData.setServiceId("unionPayDirectOrder");
            requestApiData.setHttpHeader(httpHeader);

            RequestHead requestHead = new RequestHead();
            requestHead.setRqsJrnlNo(NBOpenSDK.getRandom());

            SDKRequest request = new SDKRequest();
            request.setData(requestApiData);
            request.setHead(requestHead);

            log.info("宁波银行, 下单(unionPayDirectOrder), 参数: {}", JSON.toJSONString(request));
            SDKResponse response = NBOpenSDK.send(request);
            log.info("宁波银行, 下单(unionPayDirectOrder), 结果: {}", JSON.toJSONString(response));

            recordSave(NbBankRecordEnum.Type.UNION_PAY_DIRECT_ORDER.getCode(), request, response);

            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject data = responseJson.getJSONObject("data");

            if (!StringUtils.equals(data.getString("errorCode"), "000000")){
                log.info("宁波银行, 下单失败(unionPayDirectOrder), code:{}, msg:{}", data.getString("errorCode"), data.getString("errorMsg"));
                throw new ServiceSystemException(PerformanceResultEnum.NB_BANK_API_ERROR);
            }

            return data;

        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new ServiceSystemException(PerformanceResultEnum.NB_BANK_API_ERROR);
    }

    /**
     * 结果查询
     * 6.1交易结果查询
     * 商户号：EFT33021200556315
     * 返回结果： 90:交易不存在
     * {
     *     "data": {
     *         "chargesAmt": "",
     *         "chargesType": "",
     *         "clearDate": "",
     *         "errorCode": "000000",
     *         "errorMsg": "成功",
     *         "merId": "EFT33021200556315",
     *         "merSeqNo": "20231129135754",
     *         "payeeAcctBankName": "",
     *         "payeeAcctBankNo": "",
     *         "payeeAcctName": "",
     *         "payeeAcctNo": "",
     *         "payMethod": "",
     *         "pyerInfList": [
     *             {
     *                 "customerId": "",
     *                 "pyerAcctBankName": "",
     *                 "pyerAcctName": "",
     *                 "pyerAcctNo": "",
     *                 "signNo": "",
     *                 "transAmt": "",
     *                 "transDtTm": ""
     *             }
     *         ],
     *         "realTrxAmt": "",
     *         "transSeqNo": "",
     *         "transStatus": "90",
     *         "trxAmt": ""
     *     },
     *     "head": {
     *         "rqsJrnlNo": "15541586367762936",
     *         "rspCode": "000000",
     *         "rspDate": "2023-11-29",
     *         "rspMsg": "交易成功",
     *         "rspTime": "13:57:54:343"
     *     }
     * }
     * 返回结果： 02:交易已受理
     * {
     *     "data": {
     *         "chargesAmt": "",
     *         "chargesType": "",
     *         "clearDate": "20231129",
     *         "errorCode": "000000",
     *         "errorMsg": "成功",
     *         "merId": "EFT33021200556315",
     *         "merSeqNo": "20231129142845",
     *         "payeeAcctBankName": "宁波银行股份有限公司",
     *         "payeeAcctBankNo": "313332082914",
     *         "payeeAcctName": "客户客户",
     *         "payeeAcctNo": "860411100000759182976409",
     *         "payMethod": "4",
     *         "pyerInfList": [
     *             {
     *                 "customerId": "",
     *                 "pyerAcctBankName": "",
     *                 "pyerAcctName": "",
     *                 "pyerAcctNo": "",
     *                 "signNo": "",
     *                 "transAmt": "",
     *                 "transDtTm": ""
     *             }
     *         ],
     *         "realTrxAmt": "0",
     *         "transSeqNo": "20231129142846065496766yDTQtg2",
     *         "transStatus": "02",
     *         "trxAmt": "1.23"
     *     },
     *     "head": {
     *         "rqsJrnlNo": "15543431902274569",
     *         "rspCode": "000000",
     *         "rspDate": "2023-11-29",
     *         "rspMsg": "交易成功",
     *         "rspTime": "14:28:51:431"
     *     }
     * }
     *
     * transStatus:
     * 00:交易成功
     * 01:交易失败
     * 02:交易已受理
     * 80:订单初始状态
     * 90:交易不存在
     * 99:交易超时,须发起交易结果查询
     */
    @Override
    public JSONObject queryOrder(String merSeqNo) {
        try {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("transId", "IP01");      //交易识别码 必填
            jsonObject.put("merId", "EFT33021200556315");     //商户号 必填

            jsonObject.put("merSeqNo", merSeqNo);     //商户流水 必填

            HashMap<String,String> httpHeader = new HashMap<>();

            RequestApiData requestApiData = new RequestApiData();
            requestApiData.setAppkey(nbBankConfig.getAppKey());
            requestApiData.setData(jsonObject);
            requestApiData.setProductId("YFT");
            requestApiData.setServiceId("queryOrder");
            requestApiData.setHttpHeader(httpHeader);

            RequestHead requestHead = new RequestHead();
            requestHead.setRqsJrnlNo(NBOpenSDK.getRandom());

            SDKRequest request = new SDKRequest();
            request.setData(requestApiData);
            request.setHead(requestHead);

            log.info("宁波银行, 查询交易结果(queryOrder), 参数: {}", JSON.toJSONString(request));
            SDKResponse response = NBOpenSDK.send(request);
            log.info("宁波银行, 查询交易结果(queryOrder), 结果: {}", JSON.toJSONString(response));

            recordSave(NbBankRecordEnum.Type.QUERY_ORDER.getCode(), request, response);

            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject data = responseJson.getJSONObject("data");

            if (!StringUtils.equals(data.getString("errorCode"), "000000")){
                log.info("宁波银行, 下单失败(queryOrder), code:{}, msg:{}", data.getString("errorCode"), data.getString("errorMsg"));
                throw new ServiceSystemException(PerformanceResultEnum.NB_BANK_API_ERROR);
            }

            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }

        throw new ServiceSystemException(PerformanceResultEnum.NB_BANK_API_ERROR);
    }

    @Override
    public void recordSave(Integer type, SDKRequest request, SDKResponse response) {

        if (Objects.equals(type, NbBankRecordEnum.Type.DIRECT_BANK_TRANSFER_ORDER.getCode())) {
            RequestApiData requestData = (RequestApiData) (request.getData());
            JSONObject requestDataJson = (JSONObject) (requestData.getData());

            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject responseDataJson = responseJson.getJSONObject("data");

            recordSave(type
                    , requestDataJson.getString("merId")
                    , requestDataJson.getString("merSeqNo")
                    , responseDataJson.getString("transSeqNo")
                    , requestDataJson.getBigDecimal("trxAmt").movePointRight(2).intValue()
                    , JSON.toJSONString(request)
                    , JSON.toJSONString(response)
                    , responseDataJson.getString("errorCode")
                    , responseDataJson.getString("errorMsg")
                    , null
            );
        }
        else if (Objects.equals(type, NbBankRecordEnum.Type.UNION_PAY_DIRECT_ORDER.getCode())) {
            RequestApiData requestData = (RequestApiData) (request.getData());
            JSONObject requestDataJson = (JSONObject) (requestData.getData());

            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject responseDataJson = responseJson.getJSONObject("data");

            recordSave(type
                    , requestDataJson.getString("merId")
                    , requestDataJson.getString("merSeqNo")
                    , responseDataJson.getString("transSeqNo")
                    , requestDataJson.getBigDecimal("trxAmt").movePointRight(2).intValue()
                    , JSON.toJSONString(request)
                    , JSON.toJSONString(response)
                    , responseDataJson.getString("errorCode")
                    , responseDataJson.getString("errorMsg")
                    , null
            );
        }
        else if (Objects.equals(type, NbBankRecordEnum.Type.QUERY_ORDER.getCode())) {
            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject responseDataJson = responseJson.getJSONObject("data");

            recordSave(type
                    , responseDataJson.getString("merId")
                    , responseDataJson.getString("merSeqNo")
                    , responseDataJson.getString("transSeqNo")
                    , responseDataJson.getBigDecimal("trxAmt").movePointRight(2).intValue()
                    , JSON.toJSONString(request)
                    , JSON.toJSONString(response)
                    , null
                    , null
                    , responseDataJson.getString("transStatus")
            );
        }
        else if (Objects.equals(type, NbBankRecordEnum.Type.NOTIFY_MERCHANT.getCode())) {
            JSONObject responseJson = JSON.parseObject(JSON.toJSONString(response));
            JSONObject responseDataJson = responseJson.getJSONObject("data");

            recordSave(type
                    , responseDataJson.getString("merId")
                    , responseDataJson.getString("merSeqNo")
                    , responseDataJson.getString("transSeqNo")
                    , responseDataJson.getBigDecimal("trxAmt").movePointRight(2).intValue()
                    , JSON.toJSONString(request)
                    , JSON.toJSONString(response)
                    , null
                    , null
                    , responseDataJson.getString("transStatus")
            );
        }
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void recordSave(Integer type,
                           String merId, String merSeqNo, String transSeqNo,
                           Integer amount,
                           String param, String result,
                           String errorCode, String errorMsg,
                           String transStatus
                           ){
        NbBankRecord record = new NbBankRecord();
        record.setType(type);
        record.setMerId(merId);
        record.setMerSeqNo(merSeqNo);
        record.setTransSeqNo(transSeqNo);
        record.setAmount(amount);
        record.setParam(param);
        record.setResult(result);
        record.setErrorCode(errorCode);
        record.setErrorMsg(errorMsg);
        record.setTransStatus(transStatus);

        nbBankRecordDao.saveEntity(record);
    }

}
