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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.InoutworkCallbackEntity;
import com.crm.pay.entity.property.InoutworkPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.InoutworkService;
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.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.math.BigDecimal;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2023-01-04 11:45
 */
@Slf4j
@Service
public class InoutworkServiceImpl extends BasePayServiceImpl implements InoutworkService {

    @Autowired
    private FinanceDepositService financeDepositService;

    public static void main(String[] args) {

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"code\":\"601181\",\n" +
                "    \"signKey\":\"fb45d8bca412e51312001d2a6d80a63d\",\n" +
                "    \"callbackSignKey\":\"5245B283-E9A5-3908-9BE7-99F1199D7A2F\",\n" +
                "    \"baseUrl\":\"https://swpapi.jy6989.com/UtDepositApi/orderGateWay\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));
        System.out.println(AESUtil.decrypt("HQpLWiiebsam+vqms30zzoys6c+NdKj8A3539+wIDoZclD+5gEB1" +
                "+oA1o3vwROgctISTkS5dT1eW3QCWvdeS28xN4fsoMj/bVzWBcKQ03BvkZjq" +
                "/xSTytTOllYWPD3e9vztqBJABihL88HjEq8iEVEZyfyaZXH5MrypspZsfR/3tra6gBp+V2qjEcEw8jmB3" +
                "/WlCYITXb02O03vKWcEmuFGD8jk8fekz+YJlHME5AdJKw+KhxjmxORYQuh2JXwFDjZRb2lvSgjo4YSSuZXzA7g==",
                "bfa5559109f94c78af615bcf00d52060"));
//        Map<String, String> params = new LinkedHashMap<>(10);
//        params.put("order_amount", "23000");
//        params.put("order_id", "20221030_1667123805");
//        params.put("order_time", "1671877661");
//        params.put("code", "610001");
//        params.put("pay_currency", "KRW");
//        params.put("uid", "779998");
//        String signString = MapUtil.getStringSortByKey(params) +  "8b026795f25458920ec1ce2249ef3sa4";
//
//        System.out.println(MD5Util.getMD5(signString));

//        System.out.println("20F3F886-28A5-22A4-90CD-214CC7ADCDB1".toLowerCase(Locale.ROOT).replace("-", ""));
//        System.out.println("20F3F886-28A5-22A4-90CD-214CC7ADCDB1".toLowerCase(Locale.ROOT));
//        System.out.println("20F3F886-28A5-22A4-90CD-214CC7ADCDB1".replace("-", ""));
    }

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

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.INOUTWORK_PAY_KEY);
        //通道配置实体
        InoutworkPropertyEntity payProperty = getPayProperty(channel, InoutworkPropertyEntity.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 void callback(InoutworkCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getBill_no(),
                JSON.toJSONString(callbackEntity)));

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

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.INOUTWORK_SUCCESS_STATUS,
                        callbackEntity.getBill_no(),
                        callbackEntity.getBill_no(),
                        PayConstants.INOUTWORK_SUCCESS_STATUS, callbackEntity);

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

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


        Map<String, String> params = new LinkedHashMap<>(10);
        params.put("order_amount", String.format("%.2f", balanceTable.getTransformAmount().doubleValue()));
        params.put("order_id", balanceTable.getSerial() + "_" + balanceTable.getLogin());
        params.put("order_time", String.valueOf(balanceTable.getAddTime().getTime() / 1000));
        params.put("code", propertyEntity.getCode());
        params.put("pay_currency", balanceTable.getTransformCurrency());
        params.put("uid", String.valueOf(balanceTable.getCId()));

        String sign = getSign(propertyEntity, params);

        params.put("sign", sign);

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

        header.put("Content-Type", "application/x-www-form-urlencoded");

        log.info(String.format("send rul:%s,params:%s", propertyEntity.getBaseUrl(),
                JSON.toJSONString(params)));

        Connection.Response response = HttpUtil.post(header, propertyEntity.getBaseUrl(), 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.getString("code").equals("200")) {
            throw new ServiceException(jsonObject.getString("msg"));
        }

        String url = jsonObject.getJSONObject("data").getString("url");
        log.info(String.format("支付请求,请求orderNo:%s,请求url:%s", params.get("order_id"), url));
        return url;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @param callbackEntity
     * @return
     * @throws ServiceException
     */

    private boolean validate(InoutworkCallbackEntity callbackEntity) throws Exception {
        InoutworkPropertyEntity payProperty = getPayProperty(PayConstants.INOUTWORK_PAY_KEY, false,
                InoutworkPropertyEntity.class);

        if (!payProperty.getCode().equals(callbackEntity.getSys_no())) {
            log.error(String.format("callback--orderNo:%s,sys_no error,payProperty code is:%s,callback sys_no is:%s",
                    callbackEntity.getBill_no(), payProperty.getCode(), callbackEntity.getSys_no()));
            return false;
        }
        String signString = callbackEntity.getBill_no() + payProperty.getCallbackSignKey();

        String _sign = callbackEntity.getSign();

        String sign = MD5Util.getMD5(signString);
        log.info(String.format("callback--orderNo:%s,signString:%s,sign:%s",
                callbackEntity.getBill_no(), signString,
                sign));
        return sign.equals(_sign);
    }

    /**
     * 请求加密sign
     *
     * @param propertyEntity
     * @param params
     * @return
     * @throws ServiceException
     */
    private String getSign(InoutworkPropertyEntity propertyEntity, Map<String, String> params) throws Exception {

        String signString = MapUtil.getStringSortByKey(params) + propertyEntity.getSignKey();

        String sign = MD5Util.getMD5(signString);

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

        return sign;
    }
}
