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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.bear.BearExBodyPayCallbackEntity;
import com.crm.pay.entity.callback.bear.BearExPayCallbackEntity;
import com.crm.pay.entity.property.BearExPayPropertyEntity;
import com.crm.pay.service.BearExPayService;
import com.crm.pay.service.FinanceDepositService;
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.*;
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.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2022-11-10 11:45
 */
@Slf4j
@Service
public class BearExPayServiceImpl extends BasePayServiceImpl implements BearExPayService {

    @Autowired
    private FinanceDepositService financeDepositService;

    public static void main(String[] args) {
        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));
        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":352127,\n" +
                "    \"key\":\"a6a67a9f7812f9f3f9a7495fdfc9ac40\",\n" +
                "    \"callbackKey\":\"a6a67a9f7812f9f3f9a7495fdfc9ac40\",\n" +
                "    \"pickupUrl\":\"https://testpay.cwgvu.com/bear/ex/pickup\",\n" +
                "    \"baseUrl\":\"https://api.bear-ex.net\",\n" +
                "    \"createBuyOrder\":\"/Merchant/CreateBuyOrder\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));
    }

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

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

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

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

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

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(BearExPayCallbackEntity callbackEntity) throws Exception {
        BearExBodyPayCallbackEntity bearExBodyPayCallback = JSON.parseObject(callbackEntity.getBody(),
                BearExBodyPayCallbackEntity.class);

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

        boolean flag = validate(callbackEntity.getBody(), callbackEntity.getTimestamp(), callbackEntity.getSign());
        if (!flag) {
            throw new ServiceException(Constants.FAIL);
        }

        List<String> success = new ArrayList<>(2);
        success.add(PayConstants.BEAR_EX_E_ADMIN_FINISH_STATUS);
        success.add(PayConstants.BEAR_EX_E_FINISH_STATUS);

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(success,
                        bearExBodyPayCallback.getMerchantBuyOrderNo(),
                        bearExBodyPayCallback.getMerchantBuyOrderNo(),
                        bearExBodyPayCallback.getMerchantBuyOrderStatus(), callbackEntity);

        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(bearExBodyPayCallback.getMerchantBuyOrderMoney()));
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(BearExPayPropertyEntity propertyEntity, FinanceDepositTable balanceTable) throws Exception {

        Map<String, String> bodyMap = new HashMap<>(10);
        String merchantBuyOrderNo = String.format("%s_%d", balanceTable.getSerial(), balanceTable.getLogin());
        bodyMap.put("MerchantBuyOrderNo", merchantBuyOrderNo);
        bodyMap.put("MerchantBuyOrderMoney", String.format("%.0f",
                balanceTable.getTransformAmount().setScale(0, RoundingMode.HALF_UP).doubleValue()));
        bodyMap.put("MerchantUID", propertyEntity.getMerchantId());
        bodyMap.put("MerchantBuyOrderUniqueCode", UUIDUtil.getUUID());
        bodyMap.put("MerchantBuyOrderPayType", "1");
        bodyMap.put("MerchantBuyOrderPayerUID", String.valueOf(balanceTable.getCId()));
        bodyMap.put("MerchantBuyOrderPayerName", balanceTable.getName());
        bodyMap.put("JumpUrl", propertyEntity.getPickupUrl());

        String timestamp = DateUtil.getTimestamp();
        String bodyJsonString = JSON.toJSONString(bodyMap);
        Map<String, String> params = new HashMap<>(10);
        params.put("body", bodyJsonString);
        params.put("timestamp", timestamp);

        String sign = getSign(propertyEntity.getKey(), bodyJsonString, timestamp, merchantBuyOrderNo);
        params.put("sign", sign);

        Map<String, String> header = new HashMap<>(1);

        header.put("Content-Type", "application/json;charset=UTF-8");

        log.info(String.format("send rul:%s,params:%s",
                propertyEntity.getBaseUrl() + propertyEntity.getCreateBuyOrder(),
                JSON.toJSONString(params)));
        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + propertyEntity.getCreateBuyOrder()
                , header,
                JSON.toJSON(params));
        String body = response.body();
        log.info(String.format("get url body:%s", body));
        if (Strings.isNullOrEmpty(body)) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        JSONObject jsonObject = JSON.parseObject(body);

        if (jsonObject == null || jsonObject.size() <= 0) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }
        if (!jsonObject.getInteger("code").equals(200) || !jsonObject.getString("msg").equals("success")) {
            throw new ServiceException(jsonObject.getString("msg"));
        }
        String url = jsonObject.getJSONObject("data").getString("CheckOutUrl");
        log.info(String.format("支付请求,请求orderNo:%s,请求url:%s", merchantBuyOrderNo, propertyEntity.getBaseUrl() + url));
        return propertyEntity.getBaseUrl() + url;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @param
     * @return
     * @throws ServiceException
     */
    private boolean validate(String bodyJsonString, String timestamp, String signature) throws Exception {
        BearExPayPropertyEntity payProperty = getPayProperty(PayConstants.BEAR_EX_PAY_KEY,
                BearExPayPropertyEntity.class);

        String signString = String.format("%s%s%s", bodyJsonString, payProperty.getCallbackKey(), timestamp);

        String sign = MD5Util.getMD5(signString);

        log.info(String.format("click callback--callback body:%s,signString:%s,sign:%s", bodyJsonString,
                signString
                , sign));

        return sign.equals(signature);
    }

    /**
     * 请求加密sign
     *
     * @param
     * @return
     * @throws ServiceException
     */
    private String getSign(String key, String bodyJsonString, String timestamp, String merchantBuyOrderNo) throws Exception {

        String signString = String.format("%s%s%s", bodyJsonString, key, timestamp);
        String sign = MD5Util.getMD5(signString);

        log.info(String.format("加密处理--请求orderNo:%s,sign string:%s,sign:%s", merchantBuyOrderNo,
                signString,
                sign));

        return sign;
    }

}
