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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.callback.stic.SticPayCallbackEntity;
import com.crm.pay.entity.property.SticPayPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.SticPayService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
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.*;
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.util.LinkedHashMap;
import java.util.Map;

/**
 * @description:
 * @author: houn
 * @create: 2020-12-15 23:45
 */
@Slf4j
@Service
public class SticPayServiceImpl extends BasePayServiceImpl implements SticPayService {

    @Autowired
    private FinanceDepositService balanceService;

    public static void main(String[] args) {
        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "\t\"merchantEmail\": \"info@cwgmarkets.com\",\n" +
                "    \"merchantKey\": \"8f09dc12920866ec975c79826566770959a55e675217709e29ca6a61773d7541\",\n" +
                "\t\"successUrl\": \"https://pay.cwgvu.com/stic/pickup\",\n" +
                "    \"failureUrl\":\"https://pay.cwgvu.com/stic/pickup\",\n" +
                "    \"callbackUrl\":\"https://pay.cwgvu.com/stic/callback\",\n" +
                "    \"referrerUrl\":\"https://pay.cwgvu.com/stic/callback\",\n" +
                "\t\"interfaceVersion\": \"live\",\n" +
                "\t\"inputCharset\": \"UTF-8\",\n" +
                "\t\"signType\": \"MD5\",\n" +
                "\t\"baseUrl\": \"https://pay.sticpay.com/1.1/pay\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));
    }

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

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(balanceSaveEntity.getPayType());
        //通道配置实体
        SticPayPropertyEntity payProperty = getPayProperty(channel, SticPayPropertyEntity.class);

        balanceSaveEntity.setCurrency(channel.getCurrency());

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

        String formString = getForm(financeDepositTable, payProperty);
        //将url加入实体保存
        financeDepositTable.setFormUrl(formString);
        
        return financeDepositTable.getSerial();
    }

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

        if (callbackEntity.getCode() != null && callbackEntity.getCode().equals(-1)) {
            boolean flag = validate(callbackEntity);
            if (!flag) {
                throw new ServiceException("fail");
            }
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.STIC_SUCCESS,
                        callbackEntity.getPayParametersCallbackEntity().getOrder_no(),
                        callbackEntity.getPayParametersCallbackEntity().getTransaction_code(),
                        callbackEntity.getCode(), callbackEntity);

        balanceCallbackUpdateEntity.setNote(callbackEntity.getMessage());
//        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getPayParametersCallbackEntity
//        ().getOrder_amount()));
        /**
         * 更新数据
         */
        balanceService.updateCallback(balanceCallbackUpdateEntity);
    }

    /**
     * 获取支付url
     *
     * @param depositTable
     * @return
     * @throws ServiceException
     */
    private String getForm(FinanceDepositTable depositTable, SticPayPropertyEntity propertyEntity) throws Exception {

        Map<String, String> map = new LinkedHashMap<>(13);

        map.put("merchant_email", propertyEntity.getMerchantEmail());
        map.put("order_no", depositTable.getSerial() + "_" + depositTable.getLogin());
        map.put("order_time", DateUtil.formatTime(depositTable.getAddTime()));
        map.put("order_amount", String.format("%.2f", depositTable.getTransformAmount().doubleValue()));
        map.put("order_currency", depositTable.getTransformCurrency());

        String sign = getSign(propertyEntity, map);

        map.put("success_url", propertyEntity.getSuccessUrl());
        map.put("failure_url", propertyEntity.getFailureUrl());
        map.put("callback_url", propertyEntity.getCallbackUrl());
        map.put("referrer_url", propertyEntity.getReferrerUrl());
        map.put("interface_version", propertyEntity.getInterfaceVersion());
        map.put("input_charset", propertyEntity.getInputCharset());
        map.put("sign_type", propertyEntity.getSignType());
        map.put("sign", sign);

        String formString = PayFormUtil.getForm(propertyEntity.getBaseUrl(), map);

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

    /**
     * 验证回调参数是否被篡改
     *
     * @param callbackEntity 回调实体
     * @return
     * @throws ServiceException
     */
    private boolean validate(SticPayCallbackEntity callbackEntity) throws Exception {
        SticPayPropertyEntity payProperty = getPayProperty(PayConstants.PAY_TYPE_STIC, false,
                SticPayPropertyEntity.class);
        String sign = getSign(payProperty, callbackEntity);

        log.info(String.format("order no:%scallback result sign compare--callback sign:%s, encryption sign result:%s"
                , callbackEntity.getPayParametersCallbackEntity().getOrder_no(),
                callbackEntity.getPayParametersCallbackEntity().getSign(), sign));
        return sign.equals(callbackEntity.getPayParametersCallbackEntity().getSign());
    }

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

        String signString = MapUtil.getString(map, "key=" + propertyEntity.getMerchantKey());

        String sign = MD5Util.getMD5(signString);

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

        return sign;
    }

    /**
     * 回调请求加密sign
     *
     * @param propertyEntity 配置信息
     * @param callbackEntity 回调实体
     * @return
     * @throws ServiceException
     */
    private String getSign(SticPayPropertyEntity propertyEntity, SticPayCallbackEntity callbackEntity) {

        Map<String, String> map = new LinkedHashMap<>(7);

        map.put("merchant_email", callbackEntity.getPayParametersCallbackEntity().getMerchant_email());
        map.put("order_no", callbackEntity.getPayParametersCallbackEntity().getOrder_no());
        map.put("order_time", callbackEntity.getPayParametersCallbackEntity().getOrder_time());
        map.put("order_amount", callbackEntity.getPayParametersCallbackEntity().getOrder_amount());
        map.put("order_currency", callbackEntity.getPayParametersCallbackEntity().getOrder_currency());
        map.put("transaction_code", callbackEntity.getPayParametersCallbackEntity().getTransaction_code());
        map.put("transaction_time", callbackEntity.getPayParametersCallbackEntity().getTransaction_time());
        String signString = MapUtil.getString(map, "key=" + propertyEntity.getMerchantKey());

        String sign = MD5Util.getMD5(signString);

        log.info(String.format("回调结果加密处理--请求orderNo:%s,sign string:%s,sign:%s",
                callbackEntity.getPayParametersCallbackEntity().getOrder_no(), signString, sign));

        return sign;
    }
}
