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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.callback.ChipCallbackEntity;
import com.crm.pay.entity.chip.ChipOrderEntity;
import com.crm.pay.entity.chip.ChipResponseEntity;
import com.crm.pay.entity.property.ChipPropertyEntity;
import com.crm.pay.service.ChipService;
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.custom.info.CustomInfoEntity;
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.MapUtil;
import com.crm.rely.backend.util.SignUtil;
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.text.ParseException;
import java.util.LinkedHashMap;
import java.util.Map;

import static com.alibaba.fastjson.JSON.parseObject;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2021-01-21 11:45
 */
@Slf4j
@Service
public class ChipServiceImpl extends BasePayServiceImpl implements ChipService {

    @Autowired
    private FinanceDepositService financeDepositService;

    public static void main(String[] args) {
        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));
    }

    /**
     * 支付请求加密sign
     *
     * @param orderEntity
     * @return
     * @throws ServiceException
     */
    private static String getSignString(ChipPropertyEntity propertyEntity, ChipOrderEntity orderEntity) {


        Map<String, String> map = new LinkedHashMap<>(14);
        map.put("companyId", String.valueOf(orderEntity.getCompanyId()));
        map.put("coinQuantity", orderEntity.getCoinQuantity().stripTrailingZeros().toPlainString());
        map.put("companyOrderNum", orderEntity.getCompanyOrderNum());
        map.put("syncUrl", orderEntity.getSyncUrl());
        map.put("asyncUrl", orderEntity.getAsyncUrl());
        map.put("phone", orderEntity.getPhone());

        String signString = MapUtil.getString(MapUtil.sortByKey(map, false));
        String sign = SignUtil.signSHA256withRSA(propertyEntity.getPri(), signString);

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

        return sign;
    }

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

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(balanceSaveEntity.getPayType());
        //通道配置实体
        ChipPropertyEntity payProperty = getPayProperty(channel, ChipPropertyEntity.class);

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

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

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

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(ChipCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getCompanyOrderNum(),
                JSON.toJSONString(callbackEntity)));
        //获取配置
        ChipPropertyEntity payProperty = getPayProperty(PayConstants.CHIP_PAY_KEY, false,
                ChipPropertyEntity.class);

        //验证传输数据
        boolean flag = validate(callbackEntity, payProperty);
        if (!flag) {
            return;
        }
//        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
//                getFinanceDepositCallbackUpdateEntity(
//                        PayConstants.CHIP_SUCCESS,
//                        callbackEntity.getCompanyOrderNum(),
//                        BasePayServiceImpl.NO_CUT_APART,
//                        callbackEntity.getIntentOrderNo(),
//                        callbackEntity.getTradeStatus(), callbackEntity);
        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(
                        PayConstants.CHIP_SUCCESS,
                        callbackEntity.getCompanyOrderNum(),
                        callbackEntity.getIntentOrderNo(),
                        callbackEntity.getTradeStatus(), callbackEntity);

        if (PayConstants.CALLBACE_SUCCESS_STATUS.equals(balanceCallbackUpdateEntity.getCallbackStatus())) {

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

    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(ChipPropertyEntity propertyEntity,
                          CustomInfoEntity infoEntity, FinanceDepositTable balanceTable) throws ServiceException,
            IOException, PayValidatedException, ParseException {

        ChipOrderEntity chipOrderEntity = new ChipOrderEntity();

        chipOrderEntity.setCompanyId(propertyEntity.getCompanyId());

        chipOrderEntity.setCoinQuantity(balanceTable.getAmount().setScale(0, RoundingMode.HALF_UP));
//        chipOrderEntity.setCompanyOrderNum(balanceTable.getSerial());
        chipOrderEntity.setCompanyOrderNum(balanceTable.getSerial() + "_" + balanceTable.getLogin());
        chipOrderEntity.setPhone(infoEntity.getPhone());
        chipOrderEntity.setSyncUrl(propertyEntity.getPickupUrl());
        chipOrderEntity.setAsyncUrl(propertyEntity.getCallbackUrl());


        String sign = getSignString(propertyEntity, chipOrderEntity);

        chipOrderEntity.setSign(sign);

        String data = JSON.toJSONString(chipOrderEntity);
        log.info(String.format("chip send address:%s,request params:%s",
                propertyEntity.getBaseUrl() + propertyEntity.getAddOrder(),
                data));
        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + propertyEntity.getAddOrder(), data);
        log.info(String.format("chip Response:%s", response.body()));
        ChipResponseEntity ChipResponseEntity = parseObject(response.body(), ChipResponseEntity.class);

        if (ChipResponseEntity == null
                || ChipResponseEntity.getCode() == null
                || ChipResponseEntity.getSuccess() == null
                || !ChipResponseEntity.getCode().equals(200)
                || ChipResponseEntity.getSuccess() != true) {
            if (ChipResponseEntity != null) {
                throw new PayValidatedException(ChipResponseEntity.getMsg());
            }

            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        String url = ChipResponseEntity.getData().getLink();
        log.info(String.format("pay request,request orderNo:%s,request url:%s", chipOrderEntity.getCompanyOrderNum(),
                url));
        return url;
    }

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

        String _sign = callbackEntity.getSign();

        String signString = getSignString(payProperty, callbackEntity);
        boolean verify = SignUtil.verifySignSHA256withRSA(payProperty.getPub(), signString, callbackEntity.getSign());
        log.info(String.format("order no:%s,callback result sign compare--callback sign:%s",
                callbackEntity.getCompanyOrderNum(), _sign));
        return verify;

    }

    /**
     * 回调请求加密sign
     *
     * @param propertyEntity
     * @param callbackEntity
     * @return
     * @throws ServiceException
     */
    private String getSignString(ChipPropertyEntity propertyEntity, ChipCallbackEntity callbackEntity) {
        Map<String, String> map = new LinkedHashMap<>(13);
        map.put("companyOrderNum", callbackEntity.getCompanyOrderNum());
        map.put("intentOrderNo", callbackEntity.getIntentOrderNo());
        map.put("coinAmount", callbackEntity.getCoinAmount());
        map.put("coinSign", callbackEntity.getCoinSign());
        map.put("tradeStatus", callbackEntity.getTradeStatus());
        map.put("tradeOrderTime", callbackEntity.getTradeOrderTime());
        if (callbackEntity.getUnitPrice() != null) {
            map.put("unitPrice", callbackEntity.getUnitPrice());
        }
        if (callbackEntity.getTotal() != null) {
            map.put("total", callbackEntity.getTotal());
        }
        if (callbackEntity.getSuccessAmount() != null) {
            map.put("successAmount", callbackEntity.getSuccessAmount());
        }

        String signString = MapUtil.getString(MapUtil.sortByKey(map, false));


        return signString;
    }


}

