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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.entity.callback.AllbtpayCallbackEntity;
import com.crm.pay.entity.property.AllbtpayPropertyEntity;
import com.crm.pay.service.AllbtpayService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.custom.info.CustomInfoEntity;
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.SysRemittanceChannelTable;
import com.crm.rely.backend.util.HttpUtil;
import com.crm.rely.backend.util.MD5Util;
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.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: houn
 * @create: 2020-11-06 12:45
 */
@Slf4j
@Service
public class AllbtpayServiceImpl extends BasePayServiceImpl implements AllbtpayService {

    @Autowired
    private FinanceDepositService financeDepositService;

    /**
     * help通道支付业务逻辑 包括加密 汇率等
     *
     * @param balanceSaveEntity 支付实体
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity, CustomInfoEntity infoEntity) throws Exception {
        SysRemittanceChannelTable channel = getPayChannel(balanceSaveEntity.getPayType());

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

        balanceSaveEntity.setCurrency(channel.getCurrency());
        balanceSaveEntity.setTransformCurrency(channel.getTransformCurrency());

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

        //获取form表单数据
        String formString = getForm(payProperty, financeDepositTable, balanceSaveEntity, infoEntity);

        //将form字符串加入到实体
        financeDepositTable.setFormUrl(formString);
        return financeDepositTable.getSerial();
    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(AllbtpayCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getOrderNo(), JSON.toJSONString(callbackEntity)));

        boolean flag = validate(callbackEntity);
        if (!flag) {
            throw new ServiceException("fail");
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity = getFinanceDepositCallbackUpdateEntity(PayConstants.ALLBTPAY_SUCCESS_STATUS000,
                callbackEntity.getOrderNo(),
                callbackEntity.getTransactionId(),
                callbackEntity.getStatus(),
                callbackEntity);
        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getAccount()));
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

    /**
     * 获取支付form
     *
     * @param financeDepositTable
     * @return
     * @throws ServiceException
     */
    private String getForm(AllbtpayPropertyEntity propertyEntity, FinanceDepositTable financeDepositTable, FinanceDepositAddEntity balanceSaveEntity, CustomInfoEntity infoEntity) throws ServiceException, IOException {

        Map<String, String> map = new HashMap<>(10);
        map.put("orderNo", financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin());
        map.put("customerName", String.valueOf(infoEntity.getId()));
        map.put("customerId", String.valueOf(financeDepositTable.getCId()));
        map.put("accountType", financeDepositTable.getTransformCurrency());
        map.put("account", String.format("%.2f", financeDepositTable.getTransformAmount().doubleValue()));
        map.put("currencyType", financeDepositTable.getCurrency().toLowerCase());
        map.put("returnUrl", propertyEntity.getReturnUrl());
        map.put("notifyUrl", propertyEntity.getNotifyUrl());
        map.put("signType", propertyEntity.getSignType());
        map.put("appId", propertyEntity.getAppId());
        map.put("type", "WEB");

        String sign = getSign(propertyEntity, map);

        map.put("sign", sign);
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Content-Type", "application/x-www-form-urlencoded;charset=UTF-8");
        Connection.Response response = HttpUtil.get(propertyEntity.getBaseUrl(), headers, map);
        String formString = response.body();

        log.info(String.format("支付请求,请求orderNo:%s,请求form:%s", financeDepositTable.getSerial(), formString));

        return formString;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @param callbackEntity
     * @return
     * @throws ServiceException
     */
    private boolean validate(AllbtpayCallbackEntity callbackEntity) throws Exception {
        AllbtpayPropertyEntity payProperty = getPayProperty(PayConstants.ALLBT_PAY_TYPE, false, AllbtpayPropertyEntity.class);
        String signString = "ACCOUNT=" + callbackEntity.getAccount() + "&ACCOUNT_TYPE=" + callbackEntity.getAccountType() + "&CURRENCY_TYPE=" + callbackEntity.getCurrencyType() + "&ORDER_NO=" + callbackEntity.getOrderNo() + "&SIGN_TYPE=" + callbackEntity.getSignType() + "&STATUS=" + callbackEntity.getStatus() + "&TRANSACTIONID=" + callbackEntity.getTransactionId() + "&PRICATE_KEY" + "=" + payProperty.getPricateKey();
        String sign = MD5Util.getMD5(signString).toUpperCase();
        boolean verify = sign.equals(callbackEntity.getSign());
        log.info(String.format("支付回调加密处理--回调orderNo:%s,回调sign string:%s,sign:%s,callback sign:%s",
                callbackEntity.getOrderNo(),
                signString,
                sign,
                callbackEntity.getSign()));
        return verify;
    }

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

        String signString = "APPID=" + map.get("appId") + "&ACCOUNT=" + map.get("account") + "&ACCOUNT_TYPE=" + map.get(
                "accountType") + "&CURRENCY_TYPE=" + map.get("currencyType") + "&CUSTOMER_NAME=" + map.get(
                        "customerName") +
                "&CUSTOMER_ID=" + map.get("customerId") + "&NOTIFY_URL=" + map.get("notifyUrl") + "&ORDER_NO=" + map.get("orderNo") +
                "&RETURN_URL=" + map.get("returnUrl") + "&SIGN_TYPE=" + map.get("signType") + "&TYPE=" + map.get(
                        "type") +
                "&PRICATE_KEY=" + propertyEntity.getPricateKey();

        String sign = MD5Util.getMD5(signString).toUpperCase();

        log.info(String.format("orderNo:%s,sign string:%s,sign:%s", map.get("Reference"), signString,
                sign));

        return sign;
    }

}
