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

import com.alibaba.fastjson.JSON;
import com.crm.pay.dto.korapay.checkout.KorapayCheckoutRequestPayDto;
import com.crm.pay.dto.korapay.checkout.KorapayCheckoutRequestReferenceDto;
import com.crm.pay.entity.callback.korapay.checkout.KoraCheckoutCallbackEntity;
import com.crm.pay.entity.korapay.checkout.KorapayCheckoutRequestCustomerEntity;
import com.crm.pay.entity.korapay.checkout.KorapayCheckoutRequestEntity;
import com.crm.pay.entity.property.PorapayCheckoutPropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.KorapayCheckoutService;
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.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.AESUtil;
import com.crm.rely.backend.util.HAMCSHAUtil;
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.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @program: cwg-my-base
 * @description:
 * @author: houn
 * @create: 2023-05-12 11:45
 */
@Slf4j
@Service
public class KorapayCheckoutServiceImpl extends BasePayServiceImpl implements KorapayCheckoutService {

    @Autowired
    private FinanceDepositService financeDepositService;

    @Autowired
    private CustomInfoService customInfoService;

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

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

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

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

        String url = getUrl(payProperty, balanceTable, balanceSaveEntity);

        balanceTable.setFormUrl(url);
        
        return url;
    }

    /**
     * 回调处理数据
     *
     * @param callbackEntity
     * @throws ServiceException
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callback(KoraCheckoutCallbackEntity callbackEntity) throws Exception {

        log.info(String.format("callback ticket:%s,callback data:%s", callbackEntity.getData().getReference(),
                JSON.toJSONString(callbackEntity)));

        int status;
        switch (callbackEntity.getData().getStatus()) {
            case PayConstants.KORAPAY_SUCCESS_STATUS:
                status = PayConstants.CALLBACE_SUCCESS_STATUS;
                break;
            case PayConstants.KORAPAY_FAILED_STATUS:
                status = PayConstants.CALLBACE_FAIL_STATUS;
                break;
            default:
                status = 0;
                break;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity = new FinanceDepositCallbackUpdateEntity();
        balanceCallbackUpdateEntity.setChannelSerial(callbackEntity.getData().getReference());
        balanceCallbackUpdateEntity.setTicket(callbackEntity.getData().getReference());
        balanceCallbackUpdateEntity.setCallbackStatus(status);
        balanceCallbackUpdateEntity.setCallbackTime(new Date());
        balanceCallbackUpdateEntity.setCallbackData(JSON.toJSONString(callbackEntity));

        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getData().getAmount()));

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

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void callbackSerial(String serial) throws Exception {
        //获取配置
        PorapayCheckoutPropertyEntity payProperty = getPayProperty(PayConstants.KORAPAY_CHECKOUT_PAY, false,
                PorapayCheckoutPropertyEntity.class);

        FinanceDepositTable table = financeDepositService.getBySerial(serial);

        validateAndUpdateCallback(payProperty, table);
    }

    @Override
    public boolean validate(String wehbookData, String signature) throws Exception {
        PorapayCheckoutPropertyEntity propertyEntity = getPayProperty(PayConstants.KORAPAY_CHECKOUT_PAY,
                PorapayCheckoutPropertyEntity.class);
        String sign = HAMCSHAUtil.sha256HMAC(wehbookData, propertyEntity.getSecretKey());
        log.info(String.format("callback result sign sha256HMAC--callback sign:%s,sign:%s",
                signature, sign));
        return signature.equals(sign);

    }

    private void validateAndUpdateCallback(PorapayCheckoutPropertyEntity payProperty, FinanceDepositTable table) throws ServiceException, IOException, PayValidatedException {
        KorapayCheckoutRequestReferenceDto korapayRequestReferenceDto = getTicketData(payProperty,
                table.getSerial() + "_" + table.getLogin());

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(PayConstants.KORAPAY_CHECKOUT_SUCCESS_STATUS,
                        table.getSerial() + "_" + table.getLogin(),
                        korapayRequestReferenceDto.getData().getReference(),
                        korapayRequestReferenceDto.getData().getStatus(), korapayRequestReferenceDto);

        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(korapayRequestReferenceDto.getData().getAmount()));

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


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

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

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

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

        header.put("Authorization",
                propertyEntity.getAuthorizationBasic() + propertyEntity.getSecretKey());

        KorapayCheckoutRequestEntity entity = new KorapayCheckoutRequestEntity();
        entity.setReference(orderNo);
        entity.setCurrency(balanceTable.getTransformCurrency());
        entity.setAmount(balanceTable.getTransformAmount().divide(BigDecimal.ONE, 2, BigDecimal.ROUND_HALF_UP).floatValue());
        entity.setRedirect_url(propertyEntity.getPickupUrl() + balanceTable.getSerial());
        entity.setNotification_url(propertyEntity.getNotificationUrl() + balanceTable.getSerial());
        entity.setChannels(propertyEntity.getChannels());

        KorapayCheckoutRequestCustomerEntity customer = new KorapayCheckoutRequestCustomerEntity();
        customer.setEmail(customInfoTable.getEmail());
        entity.setCustomer(customer);
        String params = JSON.toJSONString(entity);
        Connection.Response response = HttpUtil.post(
                propertyEntity.getBaseUrl() + propertyEntity.getChargesInitializeUrl(), header, params);

        log.info(String.format("url:%s,header:%s,params:%s,body:%s",
                propertyEntity.getBaseUrl() + propertyEntity.getChargesInitializeUrl(),
                JSON.toJSON(header), params, response.body()));
        KorapayCheckoutRequestPayDto requestEntity = JSON.parseObject(response.body(),
                KorapayCheckoutRequestPayDto.class);

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

        if (!requestEntity.isStatus()) {
            if (Strings.isNullOrEmpty(requestEntity.getMessage())) {
                throw new PayValidatedException("Payment platform is abnormal, please try again later or contact " +
                        "customer" +
                        " service.");
            } else {
                throw new PayValidatedException(requestEntity.getMessage());
            }
        }
        String url = requestEntity.getData().getCheckoutUrl();
        log.info(String.format("korapay checkout,request orderNo:%s,url:%s", requestEntity.getData().getReference()
                , url));
        return url;
    }


    private KorapayCheckoutRequestReferenceDto getTicketData(PorapayCheckoutPropertyEntity propertyEntity,
                                                             String ticket) throws ServiceException,
            IOException,
            PayValidatedException {

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

        header.put("Authorization",
                propertyEntity.getAuthorizationBasic() + propertyEntity.getSecretKey());
        String url = propertyEntity.getBaseUrl() + propertyEntity.getChargesReferenceUrl() + ticket;
        Connection.Response response = HttpUtil.get(url, header);

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

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

        if (!requestEntity.isStatus()) {
            if (Strings.isNullOrEmpty(requestEntity.getMessage())) {
                throw new PayValidatedException("Payment platform is abnormal, please try again later or contact " +
                        "customer" +
                        " service.");
            } else {
                throw new PayValidatedException(requestEntity.getMessage());
            }
        }
        requestEntity.getData().setSerial(ticket);
        return requestEntity;
    }

    public static void main(String[] args) throws UnsupportedEncodingException {
        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));
//        System.out.println(AESUtil.encrypt("{\n" +
//                "    \"publicKey\":\"pk_test_FNcAsVNLjs4yBSbPdf6PjCLAXD2AeDcsHm8hcmHU\",\n" +
//                "    \"secretKey\":\"sk_test_8twiLuqJVcjCDvJe2T9PK7CL6kVifVonFgRh5dx7\",\n" +
//                "    \"encryptionKey\":\"gvwt4pujpR5atJueUAFBTiM5Con3obhE\",\n" +
//                "    \"authorizationBasic\":\"Bearer \",\n" +
//                "    \"channels\":[\"bank_transfer\",\"card\",\"pay_with_bank\"],\n" +
//                "    \"pickupUrl\":\"https://pay.cwgvu.com/korapay/checkout/pickup/\",\n" +
//                "    \"notificationUrl\":\"https://pay.cwgvu.com/korapay/checkout/callback/\",\n" +
//                "    \"baseUrl\":\"https://api.korapay.com\",\n" +
//                "    \"chargesInitializeUrl\":\"/merchant/api/v1/charges/initialize\",\n" +
//                "    \"chargesReferenceUrl\":\"/merchant/api/v1/charges/\"\n" +
//                "}", "bfa5559109f94c78af615bcf00d52060"));
////
        System.out.println(AESUtil.decrypt("",
                "bfa5559109f94c78af615bcf00d52060"));
    }
}
