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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.HuaboCallbackEntity;
import com.crm.pay.entity.property.HuaboPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.HuaboService;
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.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 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.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @description:
 * @author: houn
 * @create: 2024-10-14 23:45
 */
@Slf4j
@Service
public class HuaboServiceImpl extends BasePayServiceImpl implements HuaboService {

    @Autowired
    private FinanceDepositService balanceService;

    private List<String> stas = new ArrayList<>(2);

    HuaboServiceImpl() {
        stas.add(PayConstants.HUABO_PAY_SUCCESS_STATUS);
        stas.add(PayConstants.HUABO_PAY_CALLBACK_SUCCESS_STATUS);
    }

    public static void main(String[] args) {

        System.out.println(AESUtil.encrypt("\n", "bfa5559109f94c78af615bcf00d52060"));
        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));


    }

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

        //获取通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.HUABO_PAY_TYPE);
        HuaboPropertyEntity payProperty = getPayProperty(channel, HuaboPropertyEntity.class);


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

        //获取支付地址
        String url = getUrl(balanceTable, payProperty);
        balanceTable.setFormUrl(url);
        
        return url;
    }

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


        boolean flag = validate(callbackEntity);
        if (!flag || !queryValidateOrderInfo(callbackEntity)) {
            throw new ServiceException(Constants.FAIL);
        }
        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(stas,
                        callbackEntity.getMchOrderNo(),
                        callbackEntity.getPayOrderId(),
                        callbackEntity.getStatus(), callbackEntity);
        //计算实际金额
        BigDecimal amount = new BigDecimal(Double.valueOf(callbackEntity.getAmount()) / 100.0);

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

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(FinanceDepositTable balanceTable, HuaboPropertyEntity payProperty) throws ServiceException
            , IOException {

        Map<String, String> params = new HashMap<>(6);
        params.put("mchId", payProperty.getMchId());
        params.put("appId", payProperty.getAppId());
        params.put("productId", payProperty.getProductId());
        params.put("mchOrderNo", balanceTable.getSerial() + "_" + balanceTable.getLogin());
        params.put("currency", payProperty.getCurrency());
        params.put("amount", String.format("%.0f", balanceTable.getTransformAmount().doubleValue() * 100));
        params.put("notifyUrl", payProperty.getNotifyUrl());
        params.put("subject", String.valueOf(balanceTable.getCId()));
        params.put("body", balanceTable.getName());

        String sign = getSign(params, payProperty);
        params.put("sign", sign);

        String payUrl = payProperty.getPayUrl();

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded");


        log.info(String.format("huabo create:%s,headers:%s,data:%s", payUrl, JSON.toJSONString(headers),
                JSON.toJSONString(params)));

        Connection.Response response = HttpUtil.post(headers, payUrl, params);


        String payString = response.body();

        log.info("huabo response body:" + payString);

        JSONObject ofaDataEntity = JSON.parseObject(payString);
        if (!"SUCCESS".equals(ofaDataEntity.getString("retCode"))) {
            throw ServiceException.exception(ofaDataEntity.getString("retMsg"));
        }

        return ofaDataEntity.getJSONObject("payParams").getString("payUrl");
//        return payString;
    }

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

        Map<String, String> params = new HashMap<>(15);
        params.put("payOrderId", callbackEntity.getPayOrderId());
        params.put("mchId", callbackEntity.getMchId());
        params.put("appId", callbackEntity.getAppId());
        params.put("productId", callbackEntity.getProductId());
        params.put("mchOrderNo", callbackEntity.getMchOrderNo());
        params.put("amount", callbackEntity.getAmount());
        params.put("income", callbackEntity.getIncome());
        params.put("status", callbackEntity.getStatus());
        params.put("paySuccTime", callbackEntity.getPaySuccTime());
        params.put("backType", callbackEntity.getBackType());
        String sign = getSign(params);

        log.info(String.format("order no:%s callback result sign compare,md5--callback sign:%s,sign:%s",
                callbackEntity.getMchOrderNo(),
                callbackEntity.getSign(), sign));
        return sign.equals(callbackEntity.getSign());

    }

    private boolean queryValidateOrderInfo(HuaboCallbackEntity callbackEntity) throws Exception,
            ServiceException {
        HuaboPropertyEntity payProperty = getPayProperty(PayConstants.HUABO_PAY_TYPE,
                HuaboPropertyEntity.class);

        Map<String, String> params = new HashMap<>(6);
        params.put("mchId", payProperty.getMchId());
        params.put("mchOrderNo", callbackEntity.getMchOrderNo());
        params.put("appId", payProperty.getAppId());

        String sign = getSign(params, payProperty);

        params.put("sign", sign);

        String queryUrl = payProperty.getQueryUrl();

        Map<String, String> headers = new HashMap<>(2);
        headers.put("Content-Type", "application/x-www-form-urlencoded");


        log.info(String.format("huabo get order info url:%s,headers:%s,data:%s", queryUrl, JSON.toJSONString(headers),
                JSON.toJSONString(params)));
        Connection.Response response = HttpUtil.post(headers, queryUrl, params);

        String payString = response.body();

        log.info(String.format("huabo get order info:%s", payString));

        JSONObject orderInfo = JSON.parseObject(payString);
        if (!"SUCCESS".equals(orderInfo.getString("retCode"))) {
            return false;
        }
        callbackEntity.setStatus(orderInfo.getString("status"));
        return true;
    }

    private String getSign(Map<String, String> params) throws Exception {
        HuaboPropertyEntity payProperty = getPayProperty(PayConstants.HUABO_PAY_TYPE,
                HuaboPropertyEntity.class);

        return getSign(params, payProperty);

    }

    private String getSign(Map<String, String> params, HuaboPropertyEntity payProperty) {
        String signString = MapUtil.getStringSortByKey(params);
        signString += "&key=" + payProperty.getKey();
        String sign = MD5Util.getMD5(signString).toUpperCase();
        log.info(String.format("orderNo:%s,signString:%s,sign:%s", params.get("mchOrderNo"), signString,
                sign));

        return sign;
    }
}
