package com.crm.pay.service.impl.pay;

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.property.EvirtualpayPropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.EvirtualpayService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.rely.backend.model.pojo.table.CustomInfoTable;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.AESUtil;
import com.crm.rely.backend.util.Base64Util;
import com.crm.rely.backend.util.PayFormUtil;
import com.crm.rely.backend.util.ShaUtil;
import com.google.common.base.Strings;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2023-02-17 11:45
 */
@Slf4j
@Service
public class EvirtualpayServiceImpl extends BasePayServiceImpl implements EvirtualpayService {

    @Autowired
    private FinanceDepositService financeDepositService;

    @Autowired
    private CustomInfoService customInfoService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity) throws Exception {

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.EVIRTUALPAY_PAY_TYPE);
        //通道配置实体
        EvirtualpayPropertyEntity payProperty = getPayProperty(channel, EvirtualpayPropertyEntity.class);

        FinanceDepositTable balanceTable = financeDepositService.save(balanceSaveEntity, channel);

        String formString = getFormString(payProperty, balanceTable);
        balanceTable.setFormUrl(formString);
        
        return balanceTable.getSerial();
    }

    /**
     * 回调处理数据
     *
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(Map<String, String> callbackEntity) throws Exception {

        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.get("merchantOrder"),
                JSON.toJSONString(callbackEntity)));

        //获取配置
        EvirtualpayPropertyEntity payProperty = getPayProperty(PayConstants.EVIRTUALPAY_PAY_TYPE, false,
                EvirtualpayPropertyEntity.class);

        //验证传输数据
        boolean flag = validate(callbackEntity, payProperty);
        if (!flag) {
            throw new ServiceException(Constants.FAIL);
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.EVIRTUALPAY_PAY_SUCCESS_STATUS,
                        callbackEntity.get("merchantOrder"),
                        callbackEntity.get("requestID"),
                        callbackEntity.get("responseCode"), callbackEntity);
        if (!Strings.isNullOrEmpty(callbackEntity.get("amount"))) {

            BigDecimal amount = new BigDecimal(callbackEntity.get("amount"));

            balanceCallbackUpdateEntity.setAmount(amount);
        }
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);

    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getFormString(EvirtualpayPropertyEntity propertyEntity, FinanceDepositTable balanceTable) throws Exception {

        CustomInfoTable customInfoTable = customInfoService.getById(balanceTable.getCustomId());

        String orderNo = balanceTable.getSerial() + "_" + balanceTable.getLogin();

        Map<String, String> map = new LinkedHashMap<>(20);
        map.put("MID", propertyEntity.getMerchantId());
        map.put("API_KEY", propertyEntity.getApiKey());
        map.put("PRIVATE_KEY", propertyEntity.getRsaPriKey());
        map.put("PAYMENT_TYPE", propertyEntity.getPaymentType());
        map.put("REDIRECT_URL", propertyEntity.getReturnUrl());
        map.put("NOTIFICATION_URL", propertyEntity.getNotifyUrl() + "/" + orderNo);

        map.put("FIRST_NAME", customInfoTable.getFirstName());
        map.put("LAST_NAME", customInfoTable.getLastName());
        map.put("REQUESTID", orderNo);
        map.put("MOBILE", customInfoTable.getPhone());
        map.put("EMAIL", customInfoTable.getEmail());
        map.put("ID", customInfoTable.getIdentity());
        map.put("CITY", customInfoTable.getCity());
        map.put("COUNTRY", customInfoTable.getCountry());
        map.put("AMOUNT", String.format("%.2f", balanceTable.getTransformAmount().doubleValue()));
        map.put("CURRENCY", balanceTable.getCurrency());
        map.put("DESCRIPTION", "CWG");
        map.put("POSTAL CODE", customInfoTable.getZipCode());
        map.put("STATE CODE", customInfoTable.getState());

        String sign = getSign(propertyEntity, map);

        map.put("CHECKSUM", sign);

        String formString = PayFormUtil.getForm(propertyEntity.getVpcheckoutUrl(), map);
        log.info(String.format("evirtualpay,orderNo:%s,formString:%s", orderNo, formString));
        return formString;
    }

    public static void main(String[] args) throws Exception {


        // concat the string
//        String concatneted = "125CWGMarkets1USD";
//        //"checksum"="Base64(SHA-256(requestId+merchantId+amount+currency))"
//        byte[] sign = ShaUtil.SHAByte(ShaUtil.SHA256, concatneted);
////        System.out.println(Base64.getEncoder().encodeToString(sign));
//        String signByBase64 = Base64Util.toBase64String(sign);
//        System.out.println(signByBase64);
//
//// hash the checksum
//        MessageDigest digest = MessageDigest.getInstance("SHA-256");
//        byte[] hash = digest.digest(concatneted.getBytes(StandardCharsets.UTF_8));
//        String checkSum = Base64.getEncoder().encodeToString(hash);
//        System.out.println(checkSum);

        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));


        String concatneted = "PD202405081401068555_66752364CWGMarkets10USD";
        //"checksum"="Base64(SHA-256(requestId+merchantId+amount+currency))"
        byte[] sign = ShaUtil.SHAByte(ShaUtil.SHA256, concatneted);
        String signByBase64 = Base64Util.toBase64String(sign);
        System.out.println(signByBase64);
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @return
     * @throws ServiceException
     */
    private boolean validate(Map<String, String> callbackEntity, EvirtualpayPropertyEntity payProperty) throws Exception {

        String _sign = callbackEntity.get("signature");

        String sign = getSign(callbackEntity, payProperty);

        log.info(String.format("order no:%s,callback result sign compare--callback sign:%s, encryption sign result:%s"
                , callbackEntity.get("merchantOrder"), _sign, sign));
        return sign.equals(_sign);
    }

    /**
     * 支付请求加密sign
     *
     * @param propertyEntity
     * @return
     * @throws ServiceException
     */
    private static String getSign(EvirtualpayPropertyEntity propertyEntity, Map<String, String> map) throws Exception {

        //"checksum"="Base64(SHA-256(requestId+merchantId+amount+currency))"
        String signString = map.get("REQUESTID") + propertyEntity.getMerchantId() + map.get("AMOUNT") + map.get(
                "CURRENCY");

        byte[] sign = ShaUtil.SHAByte(ShaUtil.SHA256, signString);


        String signByBase64 = Base64Util.toBase64String(sign);
        String order = map.get("REQUESTID");

        log.info(String.format("evirtualpay--orderNo:%s,string:%s,sha256 sign string:%s,sign base64 string:%s", order
                , signString,
                sign, signByBase64));

        return signByBase64;
    }

    private static String getSign(Map<String, String> callbackEntity, EvirtualpayPropertyEntity propertyEntity) throws Exception {

        //"checksum"="Base64(SHA-256(requestId+merchantId+amount+currency))"
        String signString = callbackEntity.get("requestID") + propertyEntity.getMerchantId() + callbackEntity.get(
                "amount") + callbackEntity.get(
                "currency");
        byte[] sign = ShaUtil.SHAByte(ShaUtil.SHA256, signString);

        String signByBase64 = Base64Util.toBase64String(sign);
        String order = callbackEntity.get("requestID");

        log.info(String.format("evirtualpay--orderNo:%s,string:%s,sign base64 string:%s", order
                , signString, signByBase64));

        return signByBase64;
    }

}
