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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.callback.GroupOtcCallbackEntity;
import com.crm.pay.entity.group.otc.GroupOtcRequestEntity;
import com.crm.pay.entity.property.GroupOtcPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.GroupOtcService;
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.HttpUtil;
import com.crm.rely.backend.util.ShaUtil;
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.util.HashMap;
import java.util.Map;
import java.util.TreeMap;

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

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2020-11-11 11:45
 */
@Slf4j
@Service
public class GroupOtcServiceImpl extends BasePayServiceImpl implements GroupOtcService {

    @Autowired
    private FinanceDepositService financeDepositService;

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

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

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

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.GROUP_OTC_SUCCESS,
                        callbackEntity.getOrderid(),
                        callbackEntity.getOrderid(),
                        callbackEntity.getStatus(),callbackEntity);

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

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

        Map<String, String> params = new TreeMap();

        params.put("type", String.valueOf(propertyEntity.getType()));
        params.put("style", String.valueOf(propertyEntity.getStyle()));
        params.put("amount", String.format("%.2f", balanceTable.getTransformAmount().doubleValue()));
        params.put("username", String.valueOf(balanceTable.getCId()));
        params.put("orderid", balanceTable.getSerial() + "_" + balanceTable.getLogin());
        params.put("appid", propertyEntity.getShopNo());
        params.put("return_url", propertyEntity.getPickupUrl());
        params.put("notify_url", propertyEntity.getNotifyUrl());
        params.put("address", propertyEntity.getAddress());

        String sign = getSign(propertyEntity, params);

        params.put("sign", sign);

        Map<String, String> headers = new HashMap<>(2);
        headers.put("Content-Type", propertyEntity.getContentType());
        Connection.Response response = HttpUtil.post(headers,propertyEntity.getBaseUrl(),  params);

        GroupOtcRequestEntity groupOtcRequestEntity = parseObject(response.body(), GroupOtcRequestEntity.class);
        if (groupOtcRequestEntity == null || groupOtcRequestEntity.getStatus() == null || !groupOtcRequestEntity.getStatus().equals(1)) {

            if (groupOtcRequestEntity != null && groupOtcRequestEntity.getStatus() != null && groupOtcRequestEntity.getStatus().equals(0)) {
                throw new PayValidatedException(groupOtcRequestEntity.getErr());
            }
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer service.");
        }
        String url = groupOtcRequestEntity.getData();
        log.info(String.format("支付请求,请求orderNo:%s,请求url:%s", params.get("orderid"), url));
        return url;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @param callbackEntity
     * @return
     * @throws ServiceException
     */
    private boolean validate(GroupOtcCallbackEntity callbackEntity) throws Exception {
        GroupOtcPropertyEntity payProperty = getPayProperty(PayConstants.GROUP_OTC_TYPE_KEY, false, GroupOtcPropertyEntity.class);

        Map<String, String> params = new TreeMap();

        params.put("amount",callbackEntity.getAmount() );
        params.put("rmb", callbackEntity.getRmb());
        params.put("orderid", callbackEntity.getOrderid());
        params.put("appid", callbackEntity.getAppid());
        params.put("status", callbackEntity.getStatus());

        String _sign = callbackEntity.getSign();

        String sign = getSign(payProperty, params);

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

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

        params.remove("sign");
        StringBuilder sb = new StringBuilder();
        for (String k : params.keySet()) {
            String value = params.get(k);
            if (null != value && value.length() > 0) {
                sb.append(k);
                sb.append(value);
            }
        }
        sb.append(propertyEntity.getShopKey());
        //生成加密字符串
        String signString = sb.toString();

        //进行sha1加密
        String sign = ShaUtil.sha1(signString).toUpperCase();

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

        return sign;
    }

}
