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

import com.alibaba.fastjson.JSON;
import com.crm.pay.dto.callback.vertu.VertuResultContentDto;
import com.crm.pay.dto.callback.vertu.VertuResultDto;
import com.crm.pay.entity.callback.VertuCallbackEntity;
import com.crm.pay.entity.property.VertuPropertyEntity;
import com.crm.pay.entity.vertu.VertuPaymentresponse;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.VertuService;
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.DateUtil;
import com.crm.rely.backend.util.HttpUtil;
import com.crm.rely.backend.util.ShaUtil;
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.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @description:
 * @author: houn
 * @create: 2023-06-18 12:45
 */
@Slf4j
@Service
public class VertuServiceImpl extends BasePayServiceImpl implements VertuService {

    @Autowired
    private FinanceDepositService financeDepositService;

    /**
     * @param balanceSaveEntity 支付实体
     * @return
     * @throws Exception
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String pay(FinanceDepositAddEntity balanceSaveEntity, CustomInfoEntity infoEntity) throws Exception {
        SysRemittanceChannelTable channel = getPayChannel(balanceSaveEntity.getPayType());

        VertuPropertyEntity payProperty = getPayProperty(channel, VertuPropertyEntity.class);

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

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

        //获取form表单数据
        String url = getUrl(payProperty, financeDepositTable, balanceSaveEntity, infoEntity);

        //将form字符串加入到实体
        financeDepositTable.setFormUrl(url);
        
        return url;
    }

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

        VertuResultDto resultDto = new VertuResultDto();
        VertuResultContentDto vertuResultContentDto = new VertuResultContentDto();
        vertuResultContentDto.setMerchantTransactionId(callbackEntity.getMerchantTransactionId());
        vertuResultContentDto.setAuthenticateCode(callbackEntity.getAuthenticateCode());
        boolean flag = validate(callbackEntity);
        if (!flag) {
            vertuResultContentDto.setStatus("fail");
            resultDto.setResultCode(1);
            resultDto.setErrorMessage("validate sign fail");
            resultDto.setContent(vertuResultContentDto);
            return resultDto;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.VERTU_PAY_SUCCESS_STATUS,
                        callbackEntity.getMerchantTransactionId(),
                        callbackEntity.getPGTransactionId(),
                        callbackEntity.getStatus(),
                        callbackEntity);
        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getAmount()));
        /**
         * 更新数据
         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);

        vertuResultContentDto.setStatus("success");
        resultDto.setResultCode(1);
        resultDto.setContent(vertuResultContentDto);
        return resultDto;
    }

    /**
     * 获取支付form
     *
     * @param financeDepositTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(VertuPropertyEntity propertyEntity, FinanceDepositTable financeDepositTable,
                          FinanceDepositAddEntity balanceSaveEntity, CustomInfoEntity infoEntity) throws ServiceException,
            IOException, PayValidatedException {
        Map<String, String> header = new HashMap<>(2);
        header.put("Content-Type", "application/json");

        String merchantTransactionId = financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin();
        String datetime = DateUtil.convertDateBetweenTimeZone("GMT+7", new Date());

        Map<String, String> params = new HashMap<>(10);

        params.put("MerchantID", propertyEntity.getMerchantId());
        params.put("Currency", financeDepositTable.getTransformCurrency());
        params.put("BankCode", financeDepositTable.getBankCode());
        params.put("MerchantTransactionID", merchantTransactionId);
        params.put("ReturnUrl", propertyEntity.getReturnUrl());
        params.put("RequestUrl", propertyEntity.getNoticeUrl());
        params.put("Language", getLanguage(infoEntity.getCountry()));
        params.put("Amount", String.format("%.4f", financeDepositTable.getTransformAmount().doubleValue()));
        params.put("DateRequest", datetime);
        params.put("IPAddress", balanceSaveEntity.getIp());

        //code=VERTU_PAY_KEY_IDR_VA && bankCode=BCA
        //或者code=VERTU_PAY_KEY_MYR_IB_FPX && bankCode= ALL
        if ((PayConstants.VERTU_PAY_KEY_IDR_VA.equals(financeDepositTable.getRemittanceChannelCode()) && financeDepositTable.getBankCode().equals("BCA"))
                || PayConstants.VERTU_PAY_KEY_MYR_IB_FPX.equals(financeDepositTable.getRemittanceChannelCode())
        ) {
            params.put("ParamOptional", String.format("FirstName=%s;", infoEntity.getFirstName()));
        } else {
            params.put("ParamOptional", "");
        }

        String sign = getPaySign(propertyEntity, params);

        params.put("Signature", sign);

        String payUrl = propertyEntity.getBaseUrl() + propertyEntity.getPaymentUrl();

        Connection.Response response = HttpUtil.post(
                payUrl, header, params);

        log.info(String.format("get vertu data, url:%s,header:%s,params:%s,body:%s",
                payUrl, JSON.toJSONString(header), JSON.toJSONString(params), response.body()));

        VertuPaymentresponse vertuPaymentresponse = JSON.parseObject(response.body(), VertuPaymentresponse.class);


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

        if (vertuPaymentresponse.getResultCode() != 1) {
            if (Strings.isNullOrEmpty(vertuPaymentresponse.getErrorMessage())) {
                throw new PayValidatedException("Payment platform is abnormal, please try again later or contact " +
                        "customer" +
                        " service.");
            } else {
                throw new PayValidatedException(vertuPaymentresponse.getErrorMessage());
            }
        }
        String url = vertuPaymentresponse.getContent().getUrl();

        log.info(String.format("vertu payment,orderNo:%s,url:%s", merchantTransactionId, url));

        return url;
    }

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

        String sign = getCallbackSign(callbackEntity);
        return callbackEntity.getSignature().equals(sign);
    }

    private String getCallbackSign(VertuCallbackEntity callbackEntity) throws Exception {

        VertuPropertyEntity payProperty = getPayProperty(callbackEntity.getChannelCode(), VertuPropertyEntity.class);

        String signString = String.format("%s%s%s%s%s%s", callbackEntity.getMerchantId(),
                callbackEntity.getMerchantTransactionId(), callbackEntity.getAmount(), callbackEntity.getStatus(),
                callbackEntity.getCurrency(), payProperty.getPasskey());

        String sign;
        try {
            sign = ShaUtil.sha(ShaUtil.SHA512, signString).toUpperCase();
        } catch (Exception e) {
            sign = null;
        }

        log.info(String.format("vertu--orderNo:%s,sign string:%s,sign:%s", callbackEntity.getMerchantTransactionId(),
                signString,
                sign));

        return sign;
    }

    private String getPaySign(VertuPropertyEntity propertyEntity, Map<String, String> params) throws UnsupportedEncodingException {


        String signString = String.format("%s%s%s%s%s", params.get("MerchantID"), params.get("Amount"), params.get(
                        "BankCode"),
                DateUtil.formatDateTime(params.get("DateRequest")), propertyEntity.getPasskey());

        String sign;
        try {
            sign = ShaUtil.sha(ShaUtil.SHA512, signString).toUpperCase();
        } catch (Exception e) {
            sign = null;
        }

        log.info(String.format("vertu--orderNo:%s,sign string:%s,sign:%s", params.get(
                        "MerchantTransactionID"), signString,
                sign));

        return sign;
    }

    private String getLanguage(String country) {
        switch (country) {
            case "VN":
                return "vi-VN";
            case "TH":
                return "th-TH";
            default:
                return "en-US";
        }
    }

    public static void main(String[] args) throws Exception {

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"56F5B73680\",\n" +
                "    \"passkey\":\"D79DAA5846\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/sgbibp2p/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"1A9B88E0A2\",\n" +
                "    \"passkey\":\"CEB771200F\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/thbibp2p/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"96A06299E2\",\n" +
                "    \"passkey\":\"665B1A1B31\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/thbqrqrc/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"462F8431AB\",\n" +
                "    \"passkey\":\"B89C5A0431\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/thbqrqrp/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"829DA5972A\",\n" +
                "    \"passkey\":\"E9989A46F9\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/vbdibp2p/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"0FC6EDA2B4\",\n" +
                "    \"passkey\":\"ED200031F0\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/vndqr/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"D663848493\",\n" +
                "    \"passkey\":\"DB93C14F35\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/jpyft/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));

        System.out.println(AESUtil.encrypt("{\n" +
                "    \"merchantId\":\"519EBFF758\",\n" +
                "    \"passkey\":\"A209818E5B\",\n" +
                "    \"returnUrl\":\"https://pay.cwgvu.com/vertu/pickup\",\n" +
                "    \"noticeUrl\":\"https://pay.cwgvu.com/vertu/jpyibfo/callback\",\n" +
                "    \"baseUrl\":\" https://api.dylamicapi.com\",\n" +
                "    \"paymentUrl\":\"/fund_in/pg_session.api\"\n" +
                "}", "bfa5559109f94c78af615bcf00d52060"));


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