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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.callback.SkrillCallbackEntity;
import com.crm.pay.entity.property.SkrillPayPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.SkrillService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
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.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.AESUtil;
import com.crm.rely.backend.util.CountryUtil;
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.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: houn
 * @create: 2020-12-30 12:45
 */
@Slf4j
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
public class SkrillServiceImpl extends BasePayServiceImpl implements SkrillService {

    @Autowired
    private FinanceDepositService financeDepositService;

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

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

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

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

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

        //获取url
        String url = getUrl(payProperty, financeDepositTable, infoEntity);

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

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

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

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.SKRILL_SUCCESS_STATUS000,
                        callbackEntity.getTransaction_id(),
                        callbackEntity.getMb_transaction_id(),
                        callbackEntity.getStatus(), callbackEntity);
//        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getAmount()));
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

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

        Map<String, String> map = new HashMap<>(10);
        String language = getLanguage(infoEntity.getCountry());

        map.put("pay_to_email", propertyEntity.getShopNo());
        map.put("transaction_id", financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin());
        map.put("return_url", propertyEntity.getReturnUrl());
        map.put("cancel_url", propertyEntity.getCancelUrl());
        map.put("status_url", propertyEntity.getStatusUrl());
        map.put("status_url2", propertyEntity.getStatusUrl2());
        map.put("language", language);
        map.put("logo_url", propertyEntity.getLogoUrl());
        map.put("prepare_only", propertyEntity.getPrepareOnly());
        map.put("merchant_id", propertyEntity.getMerchantId());

        map.put("pay_from_email", infoEntity.getEmail());
        map.put("firstname", infoEntity.getFirstName());
        map.put("lastname", infoEntity.getLastName());
        map.put("country", infoEntity.getCountry());

        map.put("amount", String.format("%.2f", financeDepositTable.getTransformAmount().doubleValue()));
        map.put("currency", financeDepositTable.getTransformCurrency());
        map.put("detail1_description", propertyEntity.getDescription());
        map.put("detail1_text", financeDepositTable.getTransformCurrency());

        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl(), map);

        log.info(String.format("get retailer data,params:%s,body:%s",
                propertyEntity.getBaseUrl(), JSON.toJSONString(map), response.body()));

        String url = String.format(propertyEntity.getPayUrl(), response.body());

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

        return url;
    }

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

        String signString = callbackEntity.getMerchant_id()
                + callbackEntity.getTransaction_id()
                + MD5Util.getMD5(payProperty.getShopKey()).toUpperCase()
                + callbackEntity.getMb_amount()
                + callbackEntity.getMb_currency()
                + callbackEntity.getStatus();

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

        boolean verify = sign.equals(callbackEntity.getMd5sig().toUpperCase());
        log.info(String.format("支付回调加密处理--回调orderNo:%s,回调sign string:%s,sign:%s,callback sign:%s",
                callbackEntity.getTransaction_id(),
                signString,
                sign,
                callbackEntity.getMd5sig()));
        return verify;
    }

    private String getLanguage(String country) {

        if (CountryUtil.isCN(country)) {
            return "ZH";
        } else {
            return "EN";
        }
    }

}
