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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.callback.retailer.PayRetailerCallbackEntity;
import com.crm.pay.entity.callback.retailer.RetailerTransactionInfo;
import com.crm.pay.entity.property.PayRetailerPropertyEntity;
import com.crm.pay.entity.retailer.RetailerPayCustomerEntity;
import com.crm.pay.entity.retailer.RetailerPayEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.PayRetailerService;
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.Base64Util;
import com.crm.rely.backend.util.HttpUtil;
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.io.IOException;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2023-04-17 10:44
 */
@Slf4j
@Service
public class PayRetailerServiceImpl extends BasePayServiceImpl implements PayRetailerService {

    @Autowired
    private FinanceDepositService financeDepositService;

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

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


    }

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

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

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

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

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

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

        //验证传输数据
        RetailerTransactionInfo retailerTransactionInfo = validate(callbackEntity, payType);
        if (retailerTransactionInfo == null) {
            throw ServiceException.exception("sign error");
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(
                        PayConstants.PAY_RETAILER_SUCCESS,
                        retailerTransactionInfo.getTrackingId(),
                        retailerTransactionInfo.getUid(),
                        retailerTransactionInfo.getStatus(), callbackEntity);
        if (PayConstants.CALLBACE_SUCCESS_STATUS.equals(balanceCallbackUpdateEntity.getCallbackStatus())) {

            balanceCallbackUpdateEntity.setAmount(new BigDecimal(retailerTransactionInfo.getAmount()).divide(new BigDecimal(100), 4, BigDecimal.ROUND_DOWN));
        }
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

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

        String orderNo = balanceTable.getSerial() + "_" + balanceTable.getLogin();

        RetailerPayEntity params = new RetailerPayEntity();
        params.setPaymentMethodId(balanceTable.getBankCode());
        params.setTrackingId(orderNo);
        params.setAmount((int) (balanceTable.getAmount().doubleValue() * 100));
        params.setCurrency("USD");
        params.setCancelUrl(propertyEntity.getCancelUrl());
        params.setReturnUrl(propertyEntity.getReturnUrl());
        params.setNotificationUrl(String.format(propertyEntity.getNotificationUrl(),
                getPayCode(balanceSaveEntity.getPayType())));
        params.setTestMode(propertyEntity.isTestMode());
        params.setRecipientPixKey(infoEntity.getEmail());

        RetailerPayCustomerEntity customer = new RetailerPayCustomerEntity();
        customer.setAddress((infoEntity.getAddressLines() != null && infoEntity.getAddressLines().size() > 0) ? infoEntity.getAddressLines().get(0) : "");
        customer.setCity(infoEntity.getCity());
        customer.setCountry(infoEntity.getCountry());
        customer.setEmail(infoEntity.getEmail());
        customer.setFirstName(infoEntity.getFirstName());
        customer.setLastName(infoEntity.getLastName());
        customer.setPersonalId(infoEntity.getIdentity());
        customer.setIp(balanceSaveEntity.getIp());
        customer.setMiddleName(infoEntity.getMiddle());
        customer.setPhone(infoEntity.getPhone());


        params.setCustomer(customer);

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

        header.put("Content-Type", "application/json");
        header.put("accept", "application/json");
        header.put("Authorization",
                propertyEntity.getAuthorizationBasic() + Base64Util.toBase64String(propertyEntity.getUsername() + ":" + propertyEntity.getApiKey()));
        String url =
                propertyEntity.getBaseUrl() + propertyEntity.getTransactionUrl();
        Connection.Response response = HttpUtil.post(url, header, params);

        log.info(String.format("get retailer data, url:%s,header:%s,params:%s,body:%s",
                url, JSON.toJSONString(header), JSON.toJSONString(params), response.body()));
        if (response.statusCode() != 200) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        RetailerTransactionInfo requestEntity = JSON.parseObject(response.body(), RetailerTransactionInfo.class);


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

        if (requestEntity.getErrors() != null && requestEntity.getErrors().size() > 0) {
            if (Strings.isNullOrEmpty(requestEntity.getErrors().get(0).getErrorMessage())) {
                throw new PayValidatedException("Payment platform is abnormal, please try again later or contact " +
                        "customer" +
                        " service.");
            } else {
                throw new PayValidatedException(requestEntity.getErrors().get(0).getErrorMessage());
            }
        }

        if ("FAILED".equals(requestEntity.getStatus())) {

            throw new PayValidatedException(requestEntity.getMessage());
        }
        log.info(String.format("retailer pay,orderNo:%s,url:%s", orderNo, requestEntity.getForm().getAction()));
        return requestEntity.getForm().getAction();
    }

    private String getPayCode(String payType) throws ServiceException {
        if (Strings.isNullOrEmpty(payType)) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        switch (payType) {

            case PayConstants.PAY_RETAILER_PAY_KEY_BR:
                return "br";
            case PayConstants.PAY_RETAILER_PAY_KEY_BRW:
                return "brw";
            case PayConstants.PAY_RETAILER_PAY_KEY_CL:
                return "cl";
            case PayConstants.PAY_RETAILER_PAY_KEY_CO:
                return "co";
            case PayConstants.PAY_RETAILER_PAY_KEY_CR:
                return "cr";
            case PayConstants.PAY_RETAILER_PAY_KEY_EC:
                return "ec";
            case PayConstants.PAY_RETAILER_PAY_KEY_SV:
                return "sv";
            case PayConstants.PAY_RETAILER_PAY_KEY_MX:
                return "mx";
            case PayConstants.PAY_RETAILER_PAY_KEY_PA:
                return "pa";
            case PayConstants.PAY_RETAILER_PAY_KEY_PE:
                return "pe";
            case PayConstants.PAY_RETAILER_PAY_KEY_GT:
                return "gt";
            case PayConstants.PAY_RETAILER_PAY_KEY_AR:
                return "ar";
            default:
                return payType;
        }
    }

    private RetailerTransactionInfo validate(PayRetailerCallbackEntity callbackEntity, String payType) throws Exception {
        PayRetailerPropertyEntity propertyEntity = getPayProperty(payType, false,
                PayRetailerPropertyEntity.class);
        Map<String, String> header = new HashMap<>(3);

        header.put("Content-Type", "application/json");
        header.put("accept", "application/json");
        header.put("Authorization",
                propertyEntity.getAuthorizationBasic() + Base64Util.toBase64String(propertyEntity.getUsername() + ":" + propertyEntity.getApiKey()));
        String url =
                propertyEntity.getBaseUrl() + propertyEntity.getGetTransactionUrl() + "/" + callbackEntity.getUid();
        Connection.Response response = HttpUtil.get(url, header);

        log.info(String.format("get RetailerTransactionInfo data, url:%s,header:%s,body:%s",
                url, JSON.toJSONString(header), response.body()));
        RetailerTransactionInfo requestEntity = JSON.parseObject(response.body(), RetailerTransactionInfo.class);

        if (requestEntity == null) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }
        return requestEntity;

    }


}
