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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.BifutongPayCallbackEntity;
import com.crm.pay.entity.property.BifutongPayPropertyEntity;
import com.crm.pay.service.BifutongPayService;
import com.crm.pay.service.FinanceDepositService;
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.PayValidatedException;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.util.AESUtil;
import com.crm.rely.backend.util.HttpUtil;
import com.crm.rely.backend.util.MD5Util;
import com.crm.rely.backend.util.MapUtil;
import com.google.common.base.Strings;
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.math.RoundingMode;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2021-06-29 11:45
 */
@Slf4j
@Service
public class BifutongPayServiceImpl extends BasePayServiceImpl implements BifutongPayService {

    @Autowired
    private FinanceDepositService financeDepositService;

    public static void main(String[] args) {
        System.out.println(AESUtil.decrypt
                ("l1I5pCBkE8rClgtn60K+Cbw4FM64unSMp4ZS2jujPRTXBoj2Ge0Soboz/sIw07fOgWkcY1moUOOImFWf8CrIf1kIDmI0gHWImR" +
                        "+j+m4e/arvOqSirqSkWQoxMDXiiIMJeVunuHjBLphCs0zKQIvfap1dOObhJDb/RI" +
                        "+pkvHSsYKSURDSzmOUWPDfHc3oJqJ3VmUs4RGZ7Qy72w+JV0xZNcCCK4kF3Yr" +
                        "/bXVz4OZaI7zb3EgC0nV1mn4jvn61CULNc1g13IhId3ffctVoZfbpLWiXKNBwP8I8SE5iocLBxY0kbWL2MiNH97PyjF0JaNj2qCrQ5x4rKEqmi/2nwHrpDg==", "bfa5559109f94c78af615bcf00d52060"));
        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));
    }

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

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

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

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

        String url = getUrl(payProperty, balanceTable, balanceSaveEntity);
        balanceTable.setFormUrl(url);
        
        return url;
    }

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

        Map<String, Object> mapResult = new HashMap<>(4);
        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getApiOrderNo(),
                JSON.toJSONString(callbackEntity)));
        //获取配置
        BifutongPayPropertyEntity payProperty = getPayProperty(PayConstants.BIFUTONG_PAY_KEY, false,
                BifutongPayPropertyEntity.class);

        //验证传输数据
        boolean flag = validate(callbackEntity, payProperty);
        if (!flag) {
            mapResult.put("code", 0);
            mapResult.put("message", "validate signature fail");
            mapResult.put("data", null);
            mapResult.put("success", false);
            return mapResult;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.BIFUTONG_SUCCESS_STATUS,
                        callbackEntity.getApiOrderNo(),
                        callbackEntity.getTradeId(),
                        callbackEntity.getTradeStatus(), callbackEntity);

        BigDecimal amount = new BigDecimal(callbackEntity.getMoney());

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

        mapResult.put("code", 1);
        mapResult.put("message", "success");
        mapResult.put("data", null);
        mapResult.put("success", true);
        return mapResult;
    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(BifutongPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable,
                          FinanceDepositAddEntity balanceSaveEntity) throws ServiceException, IOException,
            PayValidatedException {

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

        Map<String, String> map = new LinkedHashMap<>(6);
        map.put("uid", propertyEntity.getUid());
        map.put("uniqueCode", String.valueOf(balanceSaveEntity.getCustomId()));
        map.put("money", String.format("%.0f",
                balanceTable.getTransformAmount().setScale(0, RoundingMode.HALF_UP).doubleValue()));
        map.put("payType", propertyEntity.getPayType());
        map.put("orderId", orderNo);

        String sign = getSign(propertyEntity, map);

        map.put("signature", sign);
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Content-Type", "application/json");

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

        log.info(String.format("url:%s,json:%s,body:%s", propertyEntity.getBaseUrl() + propertyEntity.getCnyPayUrl(),
                JSON.toJSON(map), response.body()));
        JSONObject requestEntity = JSON.parseObject(response.body());

        if (requestEntity == null
                || (requestEntity.get("code") != null && !requestEntity.get("code").toString().equals("1"))
                || (requestEntity.get("success") != null && !requestEntity.get("success").toString().equals("true"))) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        String url = String.valueOf(requestEntity.get("data"));
        log.info(String.format("支付请求,请求orderNo:%s,请求url:%s", map.get("orderId"), url));
        return url;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @param callbackEntity
     * @return
     * @throws ServiceException
     */
    private boolean validate(BifutongPayCallbackEntity callbackEntity, BifutongPayPropertyEntity payProperty) throws Exception {

        String _sign = callbackEntity.getSignature();

        String sign = getSign(payProperty, callbackEntity);

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

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

        String signString = MapUtil.getString(MapUtil.sortByKey(map, false)) + "&key=" + propertyEntity.getAccessKey();
        String sign = MD5Util.getMD5(signString);
        String order = map.get("orderId");
        if (Strings.isNullOrEmpty(order)) {
            log.info(String.format("bifutong pay response--sign string:%s,sign:%s", signString, sign));
        } else {
            log.info(String.format("orderNo:%s,sign string:%s,sign:%s", order, signString, sign));
        }


        return sign;
    }

    /**
     * 回调请求加密sign
     *
     * @param propertyEntity
     * @param callbackEntity
     * @return
     * @throws ServiceException
     */
    private String getSign(BifutongPayPropertyEntity propertyEntity, BifutongPayCallbackEntity callbackEntity) {
        Map<String, String> map = new LinkedHashMap<>(6);
        map.put("apiOrderNo", callbackEntity.getApiOrderNo());
        map.put("money", callbackEntity.getMoney());
        map.put("tradeStatus", callbackEntity.getTradeStatus());
        map.put("tradeId", callbackEntity.getTradeId());
        map.put("uniqueCode", callbackEntity.getUniqueCode());
        String signString =
                MapUtil.getString(MapUtil.sortByKey(map, false)) + "&key=" + propertyEntity.getCallbackKey();
        String sign = MD5Util.getMD5(signString);

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

        return sign;
    }
}
