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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.property.SpaysworldPayPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.SpaysworldPayService;
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.PayValidatedException;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.DateUtil;
import com.crm.rely.backend.util.MD5Util;
import com.crm.rely.backend.util.MapUtil;
import com.crm.rely.backend.util.PayFormUtil;
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.io.IOException;
import java.math.BigDecimal;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2023-02-17 11:45
 */
@Slf4j
@Service
public class SpaysworldPayServiceImpl extends BasePayServiceImpl implements SpaysworldPayService {

    @Autowired
    private FinanceDepositService financeDepositService;

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

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.SPAYSWAORLD_PAY_KEY);
        //通道配置实体
        SpaysworldPayPropertyEntity payProperty = getPayProperty(channel, SpaysworldPayPropertyEntity.class);

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

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

        String formString = getFormString(payProperty, balanceTable);
        balanceTable.setFormUrl(formString);
        
        return balanceTable.getSerial();
    }

    /**
     * 回调处理数据
     *
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(Map<String, String> callbackEntity) throws Exception {

        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.get("OrderID"),
                JSON.toJSONString(callbackEntity)));

        //获取配置
        SpaysworldPayPropertyEntity payProperty = getPayProperty(PayConstants.SPAYSWAORLD_PAY_KEY, false, SpaysworldPayPropertyEntity.class);

        //验证传输数据
        boolean flag = validate(callbackEntity, payProperty);
        if (!"1".equals(callbackEntity.get("RetStatus")) || !flag) {
            throw new ServiceException(Constants.FAIL);
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.SPAYSWORLD_SUCCESS_STATUS,
                        callbackEntity.get("OrderID"),
                        callbackEntity.get("TradeID"),
                        callbackEntity.get("RetStatus"),callbackEntity);

        BigDecimal amount = new BigDecimal(callbackEntity.get("Amt"));

        balanceCallbackUpdateEntity.setTransformAmount(amount);
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);

    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getFormString(SpaysworldPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable) throws ServiceException, IOException, PayValidatedException {

        String orderNo = balanceTable.getSerial() + "_" + balanceTable.getLogin();

        Map<String, String> map = new LinkedHashMap<>(6);
        String datetime = DateUtil.convertDateBetweenTimeZone("GMT+8", balanceTable.getAddTime(), DateUtil.DATE_TIME_FORMAT);
        map.put("TradeType", propertyEntity.getTradeType());
        map.put("OperatorID", propertyEntity.getOperatorID());
        map.put("PayType", propertyEntity.getPayType());
        map.put("BankID", "1");
        map.put("OrderID", orderNo);
        map.put("Subject", balanceTable.getName().trim());
//        map.put("Subject", balanceTable.getSerial());
        map.put("MachineIP", "127.0.0.1");
        map.put("NotifyUrl", propertyEntity.getNotifyUrl());
        map.put("ReturnUrl", propertyEntity.getReturnUrl());
        map.put("SubmitTime", datetime);
        map.put("MerchantID", propertyEntity.getMerchantID());
        map.put("Amt", String.format("%.2f", balanceTable.getTransformAmount().doubleValue()));
        map.put("Summary", String.format("%d_%d", balanceTable.getCId(), balanceTable.getLogin()));
        String sign = getSign(propertyEntity, map);

        map.put("Sign", sign);
        String formString = PayFormUtil.getForm(propertyEntity.getBaseUrl(), map);
        log.info(String.format("支付请求,请求orderNo:%s,请求formString:%s", orderNo, formString));
        return formString;
    }
    public static void main(String[] args) {
        Map<String, String> map = new LinkedHashMap<>(6);

        map.put("TradeType","bis.pay.submit");
        map.put("OperatorID", "202202250923768");
        map.put("PayType", "0303");
        map.put("BankID", "1");
        map.put("OrderID", "CWH20220302071850399_1833786");
//        map.put("Subject", balanceTable.getName().trim());
        map.put("Subject", "陈佳余");
        map.put("MachineIP", "127.0.0.1");
        map.put("NotifyUrl", "http://my.citywealth.co/Spaysworld/Notify");
        map.put("ReturnUrl", "http://my.citywealth.co/Spaysworld/Pickup");
        map.put("SubmitTime", "20220302071850");
        map.put("MerchantID", "202202250923768");
        map.put("Amt", "6370.00");
        map.put("Summary", "CWH20220302071850399_1833786");
        String signString = MapUtil.getString(MapUtil.sortByKey(map, false)) + "&Key=" + "2C7C4CFF4E897D9CE82C062125B3BB53";

        System.out.println(signString);
        String sign = MD5Util.getMD5(signString).toUpperCase();
        System.out.println(sign);
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @return
     * @throws ServiceException
     */
    private boolean validate(Map<String, String> callbackEntity, SpaysworldPayPropertyEntity payProperty) throws Exception {

        String _sign = callbackEntity.get("Sign");

        String sign = getSign(payProperty, callbackEntity);

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

    /**
     * 支付请求加密sign
     *
     * @param propertyEntity
     * @return
     * @throws ServiceException
     */
    private static String getSign(SpaysworldPayPropertyEntity propertyEntity, Map<String, String> map) {
        map.remove("Sign");
        String signString = MapUtil.getString(MapUtil.sortByKey(map, false)) + "&Key=" + propertyEntity.getKey();
        String sign = MD5Util.getMD5(signString).toUpperCase();

        String order = map.get("OrderID");

        log.info(String.format("spaysworld--orderNo:%s,string:%s,md5 sign string:%s", order, signString,
                sign));

        return sign;
    }

}
