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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.callback.BipiCallbackEntity;
import com.crm.pay.entity.property.BipiPayPropertyEntity;
import com.crm.pay.service.BipiPayService;
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.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.MapUtil;
import com.crm.rely.backend.util.ShaUtil;
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.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: houn
 * @create: 2021-12-26 23:44
 */
@Slf4j
@Service
public class BipipayServiceImpl extends BasePayServiceImpl implements BipiPayService {

    @Autowired
    private FinanceDepositService balanceService;


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

        SysRemittanceChannelTable channel = getPayChannel(PayConstants.BIPI_PAY_TYPE_KEY);

        BipiPayPropertyEntity payProperty = getPayProperty(channel, BipiPayPropertyEntity.class);

        balanceSaveEntity.setCurrency(channel.getCurrency());
        balanceSaveEntity.setTransformCurrency(channel.getTransformCurrency());
        FinanceDepositTable balanceTable = balanceService.save(balanceSaveEntity, channel);

        String url = getUrl(balanceTable, payProperty);
        balanceTable.setFormUrl(url);
        
        return url;
    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(BipiCallbackEntity callbackEntity) throws Exception {

        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getTxcode(), JSON.toJSONString(callbackEntity)));
        boolean flag = validate(callbackEntity);
        if (!flag) {
            throw new ServiceException(Constants.FAIL);
        }

        int status;
        switch (callbackEntity.getResult()) {
            case "OK":
                status = 0;
                break;
            case "Approved":
                status = 1;
                break;
            case "Fail":
                status = 2;
                break;
            default:
                status = -1;
                break;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(callbackEntity.getTxcode(), callbackEntity.getPaytxno(), status,callbackEntity);


        BigDecimal amount = new BigDecimal(callbackEntity.getAmount());
        balanceCallbackUpdateEntity.setTransformAmount(amount);

        /**
         * 更新数据
         */
        balanceService.updateCallback(balanceCallbackUpdateEntity);
    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(FinanceDepositTable balanceTable,
                          BipiPayPropertyEntity payProperty) throws Exception {

        Map<String, String> map = new HashMap<>(10);
        map.put("txcode", balanceTable.getSerial() + "_" + balanceTable.getLogin());
        map.put("merchant", payProperty.getMerchant());
        map.put("customer", String.valueOf(balanceTable.getCId()));
        map.put("currency", balanceTable.getTransformCurrency());
        map.put("amount", balanceTable.getTransformAmount().stripTrailingZeros().toPlainString());
        map.put("usdamount", balanceTable.getAmount().stripTrailingZeros().toPlainString());

//        String data = MapUtil.getStringSortByKey(map, false, true);
        String data = MapUtil.getStringSortByKey(map);

        String sign = getSign(payProperty, data);
        String url = String.format("%s?%s&signed=%s", payProperty.getBaseUrl(), data, sign);

        log.info(String.format("bipi,orderNo:%s,url:%s", map.get("txcode"), url));
        return url;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @return
     * @throws ServiceException
     */
    private boolean validate(BipiCallbackEntity callbackEntity) throws Exception {
        BipiPayPropertyEntity payProperty = getPayProperty(PayConstants.BIPI_PAY_TYPE_KEY, false, BipiPayPropertyEntity.class);

        Map<String, String> map = new HashMap<>(10);
        map.put("txcode", callbackEntity.getTxcode());
        map.put("merchant", payProperty.getMerchant());
        map.put("customer", callbackEntity.getCustomer());
        map.put("currency", callbackEntity.getCurrency());
        map.put("amount", callbackEntity.getAmount());
        map.put("paytxno", callbackEntity.getPaytxno());
        map.put("paytxtime", callbackEntity.getPaytxtime());
        map.put("result", callbackEntity.getResult());
        if ("Fail".equals(callbackEntity.getResult())) {
            map.put("error", callbackEntity.getError());
        }
//        String data = MapUtil.getStringSortByKey(map, false, true);
        String data = MapUtil.getStringSortByKey(map);

        String vSign = getSign(payProperty, data);

        log.info(String.format("callback sign,data:%s,encryption:SHA-512--callback sign:%s,callback string ShaUtil " +
                        "SHA-512:%s",
                data
                , callbackEntity.getSigned(),
                vSign));
        return vSign.equals(callbackEntity.getSigned());
    }

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

        String data = "amount=7588.00&currency=RMB &customer=66742408&merchant=ME211224A9&paytxno=W220408122622560" +
                "&paytxtime=220408122622&result=Approved&txcode=";
        String apiKey = "";
        String waitString = String.format("%s%s", data, apiKey);

//        String sign = ShaUtil.sha(ShaUtil.SHA512, waitString);
//        System.out.println(sign);
//        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));

         data = "amount=18000&currency=RMB&customer=10001&merchant=ME2333&paytxno=18080113386 68&paytxtime=180801133811&result=OK&txcode=TX3888";
         apiKey = "bipipaykey";
         waitString = String.format("%s%s", data, apiKey);

        System.out.println(ShaUtil.sha(ShaUtil.SHA512, waitString));
    }

    private String getSign(BipiPayPropertyEntity payProperty, String data) throws Exception {

        String waitString = String.format("%s%s", data, payProperty.getApiKey());

        String sign = ShaUtil.sha(ShaUtil.SHA512, waitString);
        return sign;
    }

}
