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

import com.alibaba.fastjson.JSON;
import com.crm.pay.dto.paypage.*;
import com.crm.pay.entity.callback.PayPagaCallbackEntity;
import com.crm.pay.entity.property.PayPagaPropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.PayPagaService;
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.CustomInfoTable;
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.ImageBase64ConverterUtil;
import com.crm.rely.backend.util.UUIDUtil;
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.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2024-04-20 11:45
 */
@Slf4j
@Service
public class PayPagaServiceImpl extends BasePayServiceImpl implements PayPagaService {
    @Autowired
    private FinanceDepositService financeDepositService;

    @Autowired
    private CustomInfoService customInfoService;

    @Value("${web.upload-path:./upload}")
    private String UPLOAD;

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

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

        balanceSaveEntity.setCurrency(channel.getCurrency());

        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(PayPagaCallbackEntity callbackEntity) throws Exception {

        log.info(String.format("callback orderNo:%s,callback data:%s",
                callbackEntity.getMerchantTransactionReference(), JSON.toJSONString(callbackEntity)));

        if (!PayConstants.PAYPAGA_PAY_HANDLE_PAYABLE.equals(callbackEntity.getTransactionType())) {

            return;
        }

        PayPagaPropertyEntity propertyEntity = getPayProperty(PayConstants.PAYPAGA_PAY_TYPE, false,
                PayPagaPropertyEntity.class);

        PayPageQueryRowDto payPageQueryRowDto = getQueryByCallback(callbackEntity, propertyEntity);

        if (payPageQueryRowDto == null) {
            throw new ServiceException("fail");
        }


        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.PAYPAGA_PAY_SUCCESS_STATUS,
                        callbackEntity.getMerchantTransactionReference(),
                        callbackEntity.getTransactionId(),
                        callbackEntity.getStatus(), callbackEntity);

        balanceCallbackUpdateEntity.setTransformAmount(payPageQueryRowDto.getTransactionTotal());
//        /**
//         * 更新数据
//         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

    /**
     * 获取支付url
     *
     * @param financeDepositTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(PayPagaPropertyEntity propertyEntity, FinanceDepositTable financeDepositTable) throws ServiceException, IOException, PayValidatedException {

        PayPageTokenDto payPageTokenDto = getToken(propertyEntity);

        PayPageTransactionConfigDto payPageTransactionConfigDto = getTransactionConfig(propertyEntity,
                payPageTokenDto, financeDepositTable);


        PayPagePaymentDto payPagePaymentDto = payment(propertyEntity, payPageTokenDto, payPageTransactionConfigDto,
                financeDepositTable);

        if (payPagePaymentDto.getNextStepsDetailInstructions() == null || payPagePaymentDto.getNextStepsDetailInstructions().size() <= 0) {
            log.error("payment PayPageNextStepsDetailInstructionDto is null");
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        String url = "";

        if ("PWC".equals(financeDepositTable.getBankCode().split("_")[0])) {
            for (PayPageNextStepsDetailInstructionDto nextStepsDetailInstruction :
                    payPagePaymentDto.getNextStepsDetailInstructions()) {
                if ("reference_url".equals(nextStepsDetailInstruction.getKey())) {
                    url = nextStepsDetailInstruction.getDescription();
                }
            }
        } else if ("BNKTR".equals(financeDepositTable.getBankCode().split("_")[0])) {
            /**
             * {
             *             "type": "label",
             *             "key": "CLABE",
             *             "label": "CLABE",
             *             "description": "659450001000000408"
             *         },
             *         {
             *             "type": "label",
             *             "key": "CONCEPTO",
             *             "label": "CONCEPTO",
             *             "description": "20240421-0523-009c-bc62-958768582d14"
             *         },
             *         {
             *             "type": "label",
             *             "key": "BENEFICIARIO",
             *             "label": "BENEFICIARIO",
             *             "description": "RED DE TALENTO EMPRESARIAL"
             *         },
             *         {
             *             "type": "label",
             *             "key": "MONTO",
             *             "label": "MONTO",
             *             "description": "1710.00"
             *         },
             *         {
             *             "type": "label",
             *             "key": "CENTROCOSTO",
             *             "label": "CENTROCOSTO",
             *             "description": "1"
             *         },
             */
            String CLABE = null;
            String CONCEPTO = null;
            String BENEFICIARIO = null;
            String MONTO = null;
            String CENTROCOSTO = null;
            String qrContent=null;
            for (PayPageNextStepsDetailInstructionDto nextStepsDetailInstruction :
                    payPagePaymentDto.getNextStepsDetailInstructions()) {
                switch (nextStepsDetailInstruction.getKey()) {
                    case "CLABE":
                        CLABE = nextStepsDetailInstruction.getDescription();
                        break;
                    case "CONCEPTO":
                        CONCEPTO = nextStepsDetailInstruction.getDescription();
                        break;
                    case "BENEFICIARIO":
                        BENEFICIARIO = nextStepsDetailInstruction.getDescription();
                        break;
                    case "MONTO":
                        MONTO = nextStepsDetailInstruction.getDescription();
                        break;
                    case "CENTROCOSTO":
                        CENTROCOSTO = nextStepsDetailInstruction.getDescription();
                        break;
                        case "qr_content":
                            qrContent = nextStepsDetailInstruction.getDescription();
                        break;
                    default:
                        break;
                }
            }
            if (!Strings.isNullOrEmpty(qrContent))
            {
                String fileName=UUIDUtil.getUUID()+".png";
                String middlePath="paypaga/"+financeDepositTable.getCustomId();
                String savePath = UPLOAD + "/file/" + middlePath;

                ImageBase64ConverterUtil.convertBase64ToFile(qrContent,savePath,fileName);
                url =   "/file/" + middlePath+"/"+fileName;

            }else {

                url = String.format(propertyEntity.getBankPayUrl(), CLABE, CONCEPTO, BENEFICIARIO, MONTO, CENTROCOSTO,
                        propertyEntity.getSuccessUrl(), financeDepositTable.getTransformCurrency());
            }
        }

        if (Strings.isNullOrEmpty(url)) {
            log.error("payment url is null");
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        log.info(String.format("paypage,payment orderNo:%s,url:%s",
                financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin(), url));
        return url;
    }

    private PayPageTokenDto getToken(PayPagaPropertyEntity propertyEntity) throws IOException, PayValidatedException {

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

        params.put("grant_type", propertyEntity.getGrantType());
        params.put("client_id", propertyEntity.getClientId());
        params.put("client_secret", propertyEntity.getClientSecret());

        Map<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded");

        log.info(String.format("get token send rul:%s,params:%s", propertyEntity.getAccessTokenUrl(),
                JSON.toJSONString(params)));


        Connection.Response response = HttpUtil.post(headers, propertyEntity.getAccessTokenUrl(), params);

        log.info(String.format("get token response body is:%s", response.body()));

        PayPageTokenDto payPageTokenDto = JSON.parseObject(response.body(), PayPageTokenDto.class);

        if (Strings.isNullOrEmpty(response.body()) || payPageTokenDto == null) {
            log.error(String.format("get token response body is null", response.body()));
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        return payPageTokenDto;
    }

    private PayPageTransactionConfigDto getTransactionConfig(PayPagaPropertyEntity propertyEntity,
                                                             PayPageTokenDto payPageTokenDto,
                                                             FinanceDepositTable financeDepositTable) throws IOException,
            PayValidatedException {

        Map<String, String> headers = createAuthorization(payPageTokenDto);

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

        params.put("merchant_id", propertyEntity.getMerchantId());
        params.put("country_code", financeDepositTable.getCountry());
        params.put("currency", financeDepositTable.getTransformCurrency());
        params.put("transaction_total", String.format("%.2f", financeDepositTable.getTransformAmount().doubleValue()));
        params.put("merchant_transaction_reference",
                financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin());


        log.info(String.format("order:%s,get transaction config send rul:%s,params:%s", params.get(
                        "merchant_transaction_reference"), propertyEntity.getTransactionConfigUrl(),
                JSON.toJSONString(params)));


        String data = JSON.toJSONString(params);

        Connection.Response response = HttpUtil.post(propertyEntity.getTransactionConfigUrl(), headers, data);

        log.info(String.format("order:%s,get transaction config response body is:%s", params.get(
                "merchant_transaction_reference"), response.body()));


        PayPageTransactionConfigDto payPageTransactionConfigDto = JSON.parseObject(response.body(),
                PayPageTransactionConfigDto.class);

        if (payPageTransactionConfigDto.getErrorCode() != null) {
            throw new PayValidatedException(payPageTransactionConfigDto.getMessage());
        }

        if (payPageTransactionConfigDto.getPaymentOptions() == null) {
            log.error("get transaction config is paymentOptions is null");
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

        return payPageTransactionConfigDto;
    }

    private PayPagePaymentDto payment(PayPagaPropertyEntity propertyEntity, PayPageTokenDto payPageTokenDto,
                                      PayPageTransactionConfigDto payPageTransactionConfigDto,
                                      FinanceDepositTable financeDepositTable) throws IOException,
            PayValidatedException, ServiceException {

        CustomInfoTable customInfoTable = customInfoService.getById(financeDepositTable.getCustomId());

        PayPagePaymentOptionsDto payPagePaymentOptionsDto = null;
        for (int i = 0; i < payPageTransactionConfigDto.getPaymentOptions().size(); i++) {

            if (financeDepositTable.getBankCode().split("_")[0].equals(payPageTransactionConfigDto.getPaymentOptions().get(i).getPaymentMethodCode())) {
                payPagePaymentOptionsDto = payPageTransactionConfigDto.getPaymentOptions().get(i);
                break;
            }
        }
        if (payPagePaymentOptionsDto == null) {
            log.error("get transaction config is paymentMethodCode not equals propertyEntity paymentMethodCode");
            throw new PayValidatedException("Payment platform is abnormal, please try again later or contact customer" +
                    " service.");
        }

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

        params.put("transaction_id", payPageTransactionConfigDto.getTransactionId());
        params.put("merchant_id", propertyEntity.getMerchantId());
        params.put("transaction_total", String.valueOf(payPagePaymentOptionsDto.getTransactionTotal()));
        params.put("payment_method_code", payPagePaymentOptionsDto.getPaymentMethodCode());
        params.put("currency", payPagePaymentOptionsDto.getCurrency());
        params.put("merchant_transaction_reference",
                financeDepositTable.getSerial() + "_" + financeDepositTable.getLogin());

        List<Map<String, String>> transactionFields = new ArrayList<>(3);

        Map<String, String> firstNameField = new HashMap<>(2);
        firstNameField.put("name", "first_name");
        firstNameField.put("value", customInfoTable.getFirstName());


        Map<String, String> lastNameField = new HashMap<>(2);
        lastNameField.put("name", "last_name");
        lastNameField.put("value", customInfoTable.getLastName());

        transactionFields.add(firstNameField);
        transactionFields.add(lastNameField);
        
        if ("BNKTR_BRL".equals(financeDepositTable.getBankCode())) {

            Map<String, String> cpfNumberField = new HashMap<>(2);
            cpfNumberField.put("name", "cpf_number");
            cpfNumberField.put("value", customInfoTable.getIdentity());

            transactionFields.add(cpfNumberField);
        }

        params.put("transaction_fields", transactionFields);

        Map<String, String> headers = createAuthorization(payPageTokenDto);

        log.info(String.format("order:%s, payment send rul:%s,params:%s",
                params.get("merchant_transaction_reference"), propertyEntity.getPaymentUrl(),
                JSON.toJSONString(params)));


        String data = JSON.toJSONString(params);

        Connection.Response response = HttpUtil.post(propertyEntity.getPaymentUrl(), headers, data);

        log.info(String.format("order:%s,payment response body is:%s", params.get("merchant_transaction_reference"),
                response.body()));

        PayPagePaymentDto payPagePaymentDto = JSON.parseObject(response.body(),
                PayPagePaymentDto.class);

        if (payPagePaymentDto.getErrorCode() != null) {
            throw new PayValidatedException(payPagePaymentDto.getMessage());
        }

        return payPagePaymentDto;

    }


    private PayPageQueryRowDto getQueryByCallback(PayPagaCallbackEntity callbackEntity,
                                                  PayPagaPropertyEntity propertyEntity) throws IOException,
            PayValidatedException, ServiceException {
        PayPageTokenDto payPageTokenDto = getToken(propertyEntity);

        String url = String.format(propertyEntity.getQueryUel(), propertyEntity.getMerchantId(),
                callbackEntity.getMerchantTransactionReference(), callbackEntity.getTransactionId());
        Map<String, String> headers = createAuthorization(payPageTokenDto);
        log.info(String.format("order:%s, query send rul:%s",
                callbackEntity.getMerchantTransactionReference(), url));

        Connection.Response response = HttpUtil.get(url, headers);
        log.info(String.format("order:%s,payment response body is:%s", callbackEntity.getMerchantTransactionReference(),
                response.body()));

        PayPageQueryDto payPageQueryDto = JSON.parseObject(response.body(),
                PayPageQueryDto.class);

        if (payPageQueryDto.getErrorCode() != null) {
            throw new PayValidatedException(payPageQueryDto.getMessage());
        }

        if (payPageQueryDto.getRows() == null || payPageQueryDto.getRows().size() <= 0) {
            throw ServiceException.exception("rows is null");
        }

        for (PayPageQueryRowDto row : payPageQueryDto.getRows()) {
            if (row.getMerchantTransactionReference().equals(callbackEntity.getMerchantTransactionReference())) {
                return row;
            }
        }

        return null;

    }

    private Map<String, String> createAuthorization(PayPageTokenDto payPageTokenDto) {
        Map<String, String> headers = new HashMap<>(1);
        headers.put("Authorization", payPageTokenDto.getTokenType() + " " + payPageTokenDto.getAccessToken());
        return headers;

    }


    public static void main(String[] args) {
//        System.out.println(AESUtil.decrypt("", "bfa5559109f94c78af615bcf00d52060"));
////
//        String CLABE = null;
//        String CONCEPTO = null;
//        String BENEFICIARIO = null;
//        String MONTO = null;
//        String CENTROCOSTO = null;
//        System.out.println(AESUtil.encrypt("{\n" +
//                "  \"grantType\":\"client_credentials\",\n" +
//                "  \"clientId\":\"783nvihll0t8s40gedoglid9av\",\n" +
//                "  \"clientSecret\":\"v9hhsht8fp0d493n774tn8r1icgvvhj03nn9vruk0fcqs9mtlq0\",\n" +
//                "  \"accessTokenUrl\":\"https://merchant-aut.paypaga.com/oauth2/token\",\n" +
//                "  \"transactionConfigUrl\":\"https://merchant-api.paypaga.com/transaction-config\",\n" +
//                "  \"paymentUrl\":\"https://merchant-api.paypaga.com/payment\",\n" +
//                "  \"queryUel\":\"https://merchant-api.paypaga" +
//                ".com/query/payins?merchant_id=%s&merchant_transaction_reference=%s&transaction_id=%s\",\n" +
//                "  \"merchantId\":\"d1510a57-b26f-4350-8bf6-5e0208e18a7c\",\n" +
//                "  \"bankPayUrl\":\"/pay/paypaga.html?CLABE=%s&CONCEPTO=%s&BENEFICIARIO=%s&MONTO=%s&CENTROCOSTO=%s" +
//                "&successUrl=%s&Currency=%s\",\n" +
//                "  \"successUrl\":\"/paypaga/pickup\",\n" +
//                "}", "bfa5559109f94c78af615bcf00d52060"));

        String qrContent="iVBORw0KGgoAAAANSUhEUgAAAZAAAAGQAQAAAACoxAthAAAEH0lEQVR4Xu2XQbKcMAxE5RXH4KZg35RjeIWj1zJkZpJUil0qIxVxQOix6N+NGRuPyz4bf69EnlYiTyuRp5XI00rkaSXytP5xpJrXOsaxd9tsbay29/X0ZtctViuJXEjzf93767kctgxWgwrQ51ljLJFAupW+1uUoITJqr9WRxW/dl2siHwjeW0bV0S5nctupRH6LjGO7EFe4yI1Nx0jkAxkoeRpB3pH6KHqOEIw6eKDGEtHqkppNPf9wMFESuZCoSvNA0hEiozkn/up7GUtEwyvz3e3H268RW8wZwnquz8uZiQTirisoeSDyMgOr1S/R2dXmUYm82LJ1ZERb2dLXJkPGJP7sdBIJBNe5yDTJbJO2GlaE9ahQO5EbQV6UZDPVOf0moxay/GnLL0cGTc04oh9Wvlatfr5zJ5E3pNp6+o8C3DipOg9NdvaRhmkTuUU+mPe0BuhP0PDQmA+fttapdiIUYjKMsC6pYUhHlOLuw3r7ybeJXCIPdJYhG+bkKCOSK/15wmf2vxk5pa27ceDAO7b48OTtp4H5hESEGPJW06911GY1vf1OV7vjWKmdyERc0hH9DlWl9uAEwauehvKJXIjP1OUw+iAn8kacMWRUfQ/ylyNNzjQjv9wC9C2DMWd3qb3Z+9/luxFP6z74DmlaB7sDFqWWqW291E5ESER1aovUGq7L4f+XwWoLG24igTCPjN5E3iajuuAxdqpTL7UTGTHQSbGseH2TTMrvH9dlIpfIErPaWuNFp8um/kaHP4HjeyIXMjrJLa4kWV5hLRJNuovuuvgtkZ+2JLM0hbB3uD+vbxIvN2oEPJEpslsutEVYR3wG0LRfuMhDRyI34v19aDi+RmCRt0lqOdNFJt2JBILrDENKZB8Dd7bMg8uayDuifqSV/JaQV8gu057cSmQiXkqxT67gnd1hH+Ba/a6emciFuLyz0wHvIFd9zu199Vunwp5IIJXdAR/uXQOSWidGKd1ybCITOXXZCCyTo2uHXQ4eoiCbNE/kRsYgwkPy1hlnqCpntqn2msgL4ndDRk+xh/owbIlRTeDAlm9B/nLEm5Ixxkaous35owxivun3QiKByG+4EZEldfFE8zWiPk0UfrXllyOupPEDQa87I9GDd2BQDJ9GtBO5kZN5H2ZskxU5j0fJluPSOZFAvOPDbss42YyPXle79bXq1cflZBP5WX5ryI0bWdakToYifJ8nwnBIelHuwNLXuuDJvSP1PBK5EM41sw+OzazQZMsobLgYkqclciNKcZXOTd8k1bxCZ4a5TOQXxA0Z2m76VbUxg+ZFnartI5FXxNeNDw/OT7SN+fDnmsgbMgiyr3ImrzusyO7g8pJrW9yfRyI3Ur2pYfroydEkrCqegOCJBPKoEnlaiTytRJ5WIk8rkaeVyNP6n5Af3t7YLOk4Z60AAAAASUVORK5CYII=";
        String fileName=UUIDUtil.getUUID()+".png";
        String middlePath="paypaga/"+101;
        String savePath = "../upload" + "/file/" + middlePath;

        ImageBase64ConverterUtil.convertBase64ToFile(qrContent,savePath,fileName);
        String url =   "/file/" + middlePath+"/"+fileName;
        System.out.println(url);
    }
}
