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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.dto.neteller.NetellerOrderDto;
import com.crm.pay.dto.neteller.NetellerOrderLinkDto;
import com.crm.pay.entity.callback.neteller.NetellerCallbackEntity;
import com.crm.pay.entity.neteller.*;
import com.crm.pay.entity.property.NetellerPropertyEntity;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.NetellerService;
import com.crm.pay.service.impl.base.BasePayServiceImpl;
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.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2021-03-20 11:45
 */
@Slf4j
@Service
public class NetellerServiceImpl extends BasePayServiceImpl implements NetellerService {
    @Autowired
    private FinanceDepositService financeDepositService;

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

        //通道配置
        SysRemittanceChannelTable channel = getPayChannel(PayConstants.NETELLER_PAY_TYPE);
        //通道配置实体
        NetellerPropertyEntity payProperty = getPayProperty(channel, NetellerPropertyEntity.class);

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

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

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

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(NetellerCallbackEntity callbackEntity) throws Exception {
        log.info(String.format("callback orderNo:%s,callback data:%s",
                callbackEntity.getPayload().getMerchantRefNum(), JSON.toJSONString(callbackEntity)));
        NetellerPropertyEntity propertyEntity = getPayProperty(PayConstants.NETELLER_PAY_TYPE, false,
                NetellerPropertyEntity.class);
        boolean flag = validate(callbackEntity, propertyEntity);

        if (!flag) {
            throw new ServiceException("fail");
        }
        if (PayConstants.NETELLER_PAYMENT_HANDLE_PAYABLE.equals(callbackEntity.getEventType())) {
            callbackHandlePayable(callbackEntity, propertyEntity);
            return;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.NETELLER_SUCCESS,
                        callbackEntity.getPayload().getMerchantRefNum(),
                        callbackEntity.getResourceId(),
                        callbackEntity.getEventType(), callbackEntity);

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

    private void callbackHandlePayable(NetellerCallbackEntity callbackEntity, NetellerPropertyEntity propertyEntity) throws IOException {

        Map<String, String> headers = getHeader(propertyEntity);
        String url =
                propertyEntity.getBaseUrl() + propertyEntity.getPaymenthandle() + "/" + callbackEntity.getResourceId();
        Connection.Response response =
                HttpUtil.get(url,
                        headers);
        log.info(String.format("paymenthandle请求,请求resourceId:%s,请求url:%s,返回结果:%s", callbackEntity.getResourceId(), url,
                response.body()));

        JSONObject jsonObject = JSON.parseObject(response.body());
        if (jsonObject.isEmpty()) {
            throw new RuntimeException("Payment platform is abnormal, please try again later or contact customer " +
                    "service.");
        }
        NetellerOrderDto orderDto = JSON.parseObject(response.body(), NetellerOrderDto.class);
        if (!"PAYABLE".equals(orderDto.getStatus())) {
            throw new RuntimeException("Payment platform is abnormal, please try again later or contact customer " +
                    "service.");
        }

        NetellerpayMenthubPaymentsEntity entity = createNetellerpayMenthubPaymentsEntity(callbackEntity, orderDto);
        url =
                propertyEntity.getBaseUrl() + propertyEntity.getPaymentId();
        response =
                HttpUtil.post(url, headers, entity);
        log.info(String.format("paymentId请求,请求resourceId:%s,请求url:%s,返回结果:%s", callbackEntity.getResourceId(), url,
                response.body()));
        jsonObject = JSON.parseObject(response.body());
        if (jsonObject.isEmpty()) {
            throw new RuntimeException("Payment platform is abnormal, please try again later or contact customer " +
                    "service.");
        }
//        orderDto = JSON.parseObject(response.body(), NetellerOrderDto.class);
    }

    /**
     * 获取支付url
     *
     * @param balanceTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(NetellerPropertyEntity propertyEntity, FinanceDepositTable balanceTable,
                          CustomInfoEntity infoEntity) throws ServiceException, IOException, PayValidatedException {
        NetellerOrderEntity netellerOrderEntity = createNetellerOrderEntity(propertyEntity, balanceTable, infoEntity);
        Map<String, String> headers = getHeader(propertyEntity);

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

        Connection.Response response = HttpUtil.post(payUrl, headers,
                netellerOrderEntity);
        JSONObject jsonObject = JSON.parseObject(response.body());
        log.info(String.format("NetellerServiceImpl,orderNo:%s,body:%s", balanceTable.getSerial(), response.body()));
        if (jsonObject.isEmpty() || jsonObject.get("error") != null) {
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }
        NetellerOrderDto orderDto = JSON.parseObject(response.body(), NetellerOrderDto.class);

        String url = null;
        for (NetellerOrderLinkDto netellerOrderLinkDto : orderDto.getLinks()) {
            if ("redirect_payment".equals(netellerOrderLinkDto.getRel())) {
                url = netellerOrderLinkDto.getHref();
            }
        }
        balanceTable.setChannelSerial(orderDto.getId());
        log.info(String.format("支付请求,请求orderNo:%s,请求url:%s", netellerOrderEntity.getMerchantRefNum(), url));
        return url;
    }

    private NetellerOrderEntity createNetellerOrderEntity(NetellerPropertyEntity propertyEntity,
                                                          FinanceDepositTable balanceTable, CustomInfoEntity infoEntity) {
        NetellerOrderEntity netellerOrderEntity = new NetellerOrderEntity();

        NetellerOrderBillingDetailEntity netellerOrderBillingDetailEntity = new NetellerOrderBillingDetailEntity();

        if (Strings.isNullOrEmpty(infoEntity.getCity())) {
            netellerOrderBillingDetailEntity.setCity("city");
        } else {
            netellerOrderBillingDetailEntity.setCity(infoEntity.getCity());

        }
        if (Strings.isNullOrEmpty(infoEntity.getCountry())) {
            netellerOrderBillingDetailEntity.setCountry("country");
        } else {
            String country;
            if ("CNT".equals(infoEntity.getCountry())) {
                country = "TW";
            } else if ("CNX".equals(infoEntity.getCountry())) {
                country = "HK";
            } else if ("CNA".equals(infoEntity.getCountry())) {
                country = "MO";
            } else {
                country = infoEntity.getCountry();
            }
            netellerOrderBillingDetailEntity.setCountry(country);
        }
        if (infoEntity.getAddressLines() != null && infoEntity.getAddressLines().size() >= 1) {
            netellerOrderBillingDetailEntity.setStreet(infoEntity.getAddressLines().get(0));
        } else {
            netellerOrderBillingDetailEntity.setStreet("street1");
        }
        if (infoEntity.getAddressLines() != null && infoEntity.getAddressLines().size() >= 2) {
            netellerOrderBillingDetailEntity.setStreet2(infoEntity.getAddressLines().get(1));
        } else {
            netellerOrderBillingDetailEntity.setStreet2("street2");
        }
        if (Strings.isNullOrEmpty(infoEntity.getZipCode())) {
            netellerOrderBillingDetailEntity.setZip("zipCode");
        } else {
            netellerOrderBillingDetailEntity.setZip(infoEntity.getZipCode());
        }

        netellerOrderEntity.setBillingDetails(netellerOrderBillingDetailEntity);

        NetellerOrderNetellerEntity netellerOrderNetellerEntity = new NetellerOrderNetellerEntity();
        netellerOrderNetellerEntity.setConsumerId(infoEntity.getEmail());
        netellerOrderNetellerEntity.setConsumerIdLocked(true);
        netellerOrderNetellerEntity.setDetail1Description("CWG");
        netellerOrderNetellerEntity.setDetail1Text("CWG");
        netellerOrderEntity.setNeteller(netellerOrderNetellerEntity);

        List<NetellerOrderLinkEntity> netellerOrderReturnLinkEntities = new ArrayList<>(3);
        NetellerOrderLinkEntity netellerOrderLinkEntity1 = new NetellerOrderLinkEntity();
        netellerOrderLinkEntity1.setHref(propertyEntity.getCompletedUrl());
        netellerOrderLinkEntity1.setRel("on_completed");
        netellerOrderReturnLinkEntities.add(netellerOrderLinkEntity1);
        NetellerOrderLinkEntity netellerOrderLinkEntity2 = new NetellerOrderLinkEntity();
        netellerOrderLinkEntity2.setHref(propertyEntity.getFailedUrl());
        netellerOrderLinkEntity2.setRel("on_failed");
        netellerOrderReturnLinkEntities.add(netellerOrderLinkEntity2);
        NetellerOrderLinkEntity netellerOrderLinkEntity3 = new NetellerOrderLinkEntity();
        netellerOrderLinkEntity3.setHref(propertyEntity.getDefaultUrl());
        netellerOrderLinkEntity3.setRel("default");
        netellerOrderReturnLinkEntities.add(netellerOrderLinkEntity3);
        netellerOrderEntity.setReturnLinks(netellerOrderReturnLinkEntities);

        netellerOrderEntity.setMerchantRefNum(balanceTable.getSerial() + "_" + balanceTable.getLogin());
        netellerOrderEntity.setTransactionType(propertyEntity.getTransactionType());
        netellerOrderEntity.setPaymentType(propertyEntity.getPaymentType());
        netellerOrderEntity.setAmount(String.format("%.0f", balanceTable.getTransformAmount().doubleValue() * 100));
        netellerOrderEntity.setCurrencyCode(balanceTable.getTransformCurrency());
        netellerOrderEntity.setCustomerIp(!Strings.isNullOrEmpty(balanceTable.getAddIp()) ?
                balanceTable.getAddIp().split("-")[0] : "");
        return netellerOrderEntity;
    }

    private NetellerpayMenthubPaymentsEntity createNetellerpayMenthubPaymentsEntity(NetellerCallbackEntity callbackEntity, NetellerOrderDto orderDto) {
        NetellerpayMenthubPaymentsEntity entity = new NetellerpayMenthubPaymentsEntity();

        entity.setMerchantRefNum(callbackEntity.getPayload().getMerchantRefNum());
        entity.setAmount(callbackEntity.getPayload().getAmount());
        entity.setCurrencyCode(callbackEntity.getPayload().getCurrencyCode());
        entity.setDupCheck(true);
        entity.setSettleWithAuth(true);
        entity.setPaymentHandleToken(orderDto.getPaymentHandleToken());
        entity.setCustomerIp(orderDto.getCustomerIp());
        entity.setDescription("CWG");
        entity.setPaymentType("NETELLER");
        return entity;
    }

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

        if (propertyEntity.getCallbackIps() == null || propertyEntity.getCallbackIps().size() <= 0) {
            return true;
        }
        return propertyEntity.getCallbackIps().contains(callbackEntity.getCallbackIp());
    }

    private Map<String, String> getHeader(NetellerPropertyEntity propertyEntity) {
        String authorization = null;
        if (Strings.isNullOrEmpty(propertyEntity.getApiKey())) {
            authorization =
                    Base64Util.toBase64String(propertyEntity.getUsername() + ":" + propertyEntity.getPassword());
        } else {
            authorization = propertyEntity.getApiKey();
        }
        Map<String, String> headers = new HashMap<>(3);
        headers.put("Content-Type", "application/json");
        headers.put(propertyEntity.getSimulatorName(), propertyEntity.getSimulator());
        headers.put(propertyEntity.getAuthorizationName(), propertyEntity.getBasic() + " " + authorization);
        return headers;
    }

    public static void main(String[] args) {
        System.out.println(AESUtil.decrypt("IfFXFAT9uoSUMQ8Q33/LbObJXydtjUybjyp" +
                "+SG1k1n2LT6MwzYmysDr23blc72cfeXaePsOHWaAIW8IRnm42t2jCogQky0JnceXZoZ62qUOIwdSMT79vjTHOIwTrZRHQwJLHB3FUfh8RrkAmb/+SJl05waJbzbZOsF8JiLr7Qo48kRw+QJp7UujHs2uWD/+0CD4pxNyEYgnk50NoMMF8JiUt0ZXrxNWNw+hojCpynD6x2DWDhZdJTsT43CCNF4Wvtv6TiHf6VAiJK3OciMrgzH2KtSo1Wm+xtNtEAnotctY+2S8V4U6OxFlSiSePiUWpNVoQiVrpnWMGUKxRLOxqBIuMqYHqzTubqzXvKIftyog0Pm4qL94hCF8T674WTvG3P9aLkMHosXEdY1Nm2IW46rOQE0r7YMGfHliM8LCmLbYgM/O6BOkK7bJP+pr7AmNpt15YTBHUC5qRT8u/Dx4Y99PCO8jNc1Tc5zNeE10TUlMY6UVUcpHWqkYMMsKfneAC+OwmwDvXxpYcmjy6yJpyuEv6MZ5I/luf4EeuzL5VjXBswDG8Pvz9jUQClbrf+OBTIq+L+Z5BICCBCZ/Cwaw14NHyyluHOze15b6MKLLDyZcKyOAdVDamSxTHYYgJX4YDEBnxtF9BxiMOgfLD6O1TI6KHRmNT8G+byd6BWU7l8oLEra+y35yuWy1GuA0nP8uVm659521xKKCrhON7JcDNXzhAnN5LMEGCQTeEx72zJZF6AF2sd/2fcmGnH3bpEtBVX6+zTBoEwjxb+wncoiIaVyUCWrpdPjKpNSzzYz/lhN/yIG4C7o6ddPu+m/ZZBgYCNR7xyDu+gZ3nDxs9KKl4sAsBDaHmrtHivPGnFP7DWaut7Ee48/N9hk9hHUyRS/R3TS2MFZF3mQoiPsg8yDDZZdtGQNGV13hXYPbtsjP0x6HmazF5YF4GEUSTNq1N8LUJ58IswHlJ043cc8/pkMTn0w==", "bfa5559109f94c78af615bcf00d52060"));
//
//        System.out.println(AESUtil.encrypt("{\n" +
//                "    \"baseUrl\":\"https://cn-payment.my5pay.com/f2fOrder/checkout\",\n" +
//                "    \"baseUrlEn\":\"https://en-payment.my5pay.com/f2fOrder/checkout\",\n" +
//                "    \"merchantId\":\"53439\",\n" +
//                "    \"notifyUrl\":\"https://pay.cwgvu.com/5pay/f2f/callback\",\n" +
//                "    \"returnUrl\":\"https://pay.cwgvu.com/5pay/pickup\",\n" +
//                "    \"secretKey\":\"lOoqhiE5sga0wmkiewO8N9b4\"\n" +
//                "}", "bfa5559109f94c78af615bcf00d52060"));
    }
}
