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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.entity.alpha.AlphaPayRateDataEntity;
import com.crm.pay.entity.alpha.AlphaPayRateEntity;
import com.crm.pay.entity.alpha.AlphaPayUrlDataEntity;
import com.crm.pay.entity.alpha.AlphaPayUrlEntity;
import com.crm.pay.entity.callback.alpha.AlphaCallbackEntity;
import com.crm.pay.entity.property.AlphaPayPropertyEntity;
import com.crm.pay.service.AlphaService;
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.core.exception.ServiceException;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.deposit.FinanceDepositAddEntity;
import com.crm.rely.backend.model.pojo.table.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysChannelBankTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.util.AESUtil;
import com.crm.rely.backend.util.HAMCSHAUtil;
import com.crm.rely.backend.util.HttpUtil;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Connection;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static com.alibaba.fastjson.JSON.parseObject;

/**
 * @description:
 * @author: houn
 * @create: 2021-10-19 23:44
 */
@Slf4j
@Service
public class AlphaServiceImpl extends BasePayServiceImpl implements AlphaService {

    @Autowired
    private FinanceDepositService balanceService;

    private final static List<String> usdtCurrencys;

    static {
        usdtCurrencys = new ArrayList<>(2);
        usdtCurrencys.add("USDTE");
        usdtCurrencys.add("USDTT");
    }

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

        SysRemittanceChannelTable channel = getPayChannel(PayConstants.ALPHA_PAY_TYPE_KEY);

        AlphaPayPropertyEntity payProperty = getPayProperty(channel, AlphaPayPropertyEntity.class);
        SysChannelBankTable channelBankTable = balanceService.getChannelBank(balanceSaveEntity, channel);
        BigDecimal rate;

        rate = getRate(channel, channelBankTable, payProperty);
        balanceSaveEntity.setRate(rate);

        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(AlphaCallbackEntity callbackEntity, String key, String sign) throws Exception {

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

        int status;
        switch (callbackEntity.getStatus()) {
            case "not_confirmed":
                status = 0;
                break;
            case "confirmed":
                status = 1;
                break;
            default:
                status = -1;
                break;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(callbackEntity.getCrypto_address().getForeign_id(),
                        callbackEntity.getId() + "", status, callbackEntity);


        if (callbackEntity.getTransactions() == null || callbackEntity.getTransactions().size() < 1) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        BigDecimal amount = new BigDecimal(callbackEntity.getTransactions().get(0).getAmount());
        balanceCallbackUpdateEntity.setTransformAmount(amount);

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

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

        Map<String, String> header = new HashMap<>(3);

        header.put("X-Processing-Key", payProperty.getProcessingKey());
        header.put("Content-Type", "application/json");

        Map<String, String> params = new HashMap<>(3);
        params.put("currency", balanceTable.getTransformCurrency());
        params.put("foreign_id", String.format("%s_%d", balanceTable.getSerial(), balanceTable.getLogin()));

        String data = JSON.toJSONString(params);
        log.info(String.format("AlphaPay发送地址%s,请求数据:%s", payProperty.getBaseUrl() + payProperty.getAddressesTake(),
                data));

        String sign = getSign(payProperty, data);
        header.put("X-Processing-Signature", sign);

        Connection.Response response = HttpUtil.post(payProperty.getBaseUrl() + payProperty.getAddressesTake(),
                header, data);
        String payString = response.body();

        log.info("AlphaPay接收发送地址返回数据:" + payString);

        AlphaPayUrlDataEntity urlDataEntity = parseObject(payString, AlphaPayUrlDataEntity.class);
        if (urlDataEntity == null || urlDataEntity.getData() == null) {
            throw ServiceException.exception();
        }
        AlphaPayUrlEntity urlEntity = urlDataEntity.getData();

        return String.format(payProperty.getPayUrl(), urlEntity.getAddress(), payProperty.getSuccessUrl(),
                String.valueOf(balanceTable.getTransformAmount()), balanceTable.getTransformCurrency());

    }

    /**
     * 验证回调参数是否被篡改
     *
     * @return
     * @throws ServiceException
     */
    private boolean validate(AlphaCallbackEntity callbackEntity, String key, String sign) throws Exception {
        AlphaPayPropertyEntity payProperty = getPayProperty(PayConstants.ALPHA_PAY_TYPE_KEY, false,
                AlphaPayPropertyEntity.class);
        if (!payProperty.getProcessingKey().equals(key)) {
            throw ServiceException.exception(Constants.NOT_PERMIT);
        }
        String data = JSON.toJSONString(callbackEntity, SerializerFeature.SortField.MapSortField,
                SerializerFeature.WriteMapNullValue);
        String vSign = getSign(payProperty, data);

        if (!vSign.equals(sign)) {
            data = data.replace(",\"riskscore\":null", "");
            vSign = getSign(payProperty, data);
        }
        log.info(String.format("callback result sign compare,data:%s,加密方式:HAMCSHA512--callback sign:%s,callback " +
                        "string HAMCSHA512Util:%s", data
                , sign,
                vSign));
        return vSign.equals(sign);
    }

    public static void main(String[] args) {

        System.out.println(AESUtil.decrypt("RD7EYg93cTWYEjJSsiFAs9pH77smSxg70TCfjofd2FH7bTMqjJhTEFCnkKcH" +
                "/oY3fULuJVNaucD+Km+DbWaeXIdJPEd+KrLhZzqPKxzTNbDzrTP1E6N1ZfTTgUHolBc3eYHzFo4lXME9Ds9MqTxlYh9IXz" +
                "/WT3LrnfZB9AgnOAWQ5xCHmUNuGmD1" +
                "+khViii6k9NSpciHDQm1t3Ie0GaNSoyrX9N9MGLLtTz6t6uUnSkZWPPFmnybAu0p51KOA96cO5mLuaMJuULpYeGiiVoN47voRAFwfhlrJ81xb/Fn8XSVM/E2Bfwp2ox8HenbX8Lgn1n/zCiwN6ccsMCgl6rSjKXXfCYZWIxMEJovQdtVpoGiAHUM51ov4AbEojUxgc/eiOQtHm7R+36jKKnJe5resQ54c/w9Epa/2OgNnpKP2U3UJKwStKR/lbrszBFruhTYsOt7rg73aGAZ3nztz3zqxBtF1TgJpXt6vz44mCfHJMGDXlc31ydLD/injm8KF0cPbmosquS8IaPhaS5n4vYW+C+JaLmgXGawUx/nyw+dj1aNUPU5AlmzIjpO95xZiif7YCM5v0oVwIPfGHA/IC+kzg==", "bfa5559109f94c78af615bcf00d52060"));
        System.out.println(AESUtil.encrypt("{\n" +
                "    \"baseUrl\":\"https://app.alphapo.net/api/v2\",\n" +
                "    \"addressesTake\":\"/addresses/take\",\n" +
                "    \"processingKey\":\"I3nk9eASkb8jPthNKVOk6Up12V4I5aXw\",\n" +
                "    \"secret\":\"3OEDgpgXxS9mSyFB9lTq1u5GUvQL28oS9J3xmVNOGpWjVJnwTqsvPSPVzZIxuje5\",\n" +
                "    \"currenciesPairs\":\"/currencies/pairs\",\n" +
                "    \"successUrl\":\"https://pay.cwgvu.com/alpha/pickup\",\n" +
                "    \"payUrl\":\"https://secure.cwgmarkets.com/pay/alpha" +
                ".html?addresses=%s&successUrl=%s&amount=%s&currency=%s\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));
    }

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

        String sign = HAMCSHAUtil.sha512HMAC(data, payProperty.getSecret());
        return sign;
    }

    private BigDecimal getRate(SysRemittanceChannelTable channel, SysChannelBankTable channelBankTable,
                               AlphaPayPropertyEntity payProperty) throws Exception {

        //特殊要求 如果是usdt-erc和trc两种 则直接返回汇率1
        if (usdtCurrencys.contains(channelBankTable.getCurrency())) {
            return BigDecimal.ONE;
        }

        Map<String, String> header = new HashMap<>(3);

        header.put("X-Processing-Key", payProperty.getProcessingKey());
        header.put("Content-Type", "application/json");

        Map<String, String> params = new HashMap<>(3);
        params.put("currency_from", channel.getCurrency());
//        params.put("currency_to", channelBankTable.getCurrency());

        String data = JSON.toJSONString(params);
        log.info(String.format("AlphaPay发送地址%s,请求数据:%s", payProperty.getBaseUrl() + payProperty.getCurrenciesPairs(),
                data));

        String sign = getSign(payProperty, data);
        header.put("X-Processing-Signature", sign);

        Connection.Response response = HttpUtil.post(payProperty.getBaseUrl() + payProperty.getCurrenciesPairs(),
                header, data);
        String payString = response.body();

        log.info("AlphaPay接收发送地址返回数据Rate:" + payString);
        AlphaPayRateDataEntity dataEntity = JSON.parseObject(payString, AlphaPayRateDataEntity.class);
        BigDecimal rate = null;
        if (dataEntity != null && dataEntity.getData() != null && dataEntity.getData().size() > 0) {
            for (AlphaPayRateEntity rateEntity : dataEntity.getData()) {
                if (channel.getCurrency().equals(rateEntity.getCurrency_from().getCurrency())
                        && channelBankTable.getCurrency().equals(rateEntity.getCurrency_to().getCurrency())) {
                    rate = new BigDecimal(rateEntity.getRate_from()).divide(new BigDecimal(rateEntity.getRate_to()),
                            10, 0);
                    break;
                }
                if (channel.getCurrency().equals(rateEntity.getCurrency_to().getCurrency())
                        && channelBankTable.getCurrency().equals(rateEntity.getCurrency_from().getCurrency())) {
                    rate = new BigDecimal(rateEntity.getRate_to()).divide(new BigDecimal(rateEntity.getRate_from()),
                            10, 0);
                    break;
                }
            }
        }
        return rate;
    }

}
