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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.PayOkCallbackEntity;
import com.crm.pay.entity.property.PayOkPropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.PayOkService;
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.*;
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.RoundingMode;
import java.text.ParseException;
import java.util.HashMap;
import java.util.Map;

import static com.alibaba.fastjson.JSON.parseObject;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2024-04-29 11:45
 */
@Slf4j
@Service
public class PayOkServiceImpl extends BasePayServiceImpl implements PayOkService {

    @Autowired
    private FinanceDepositService financeDepositService;

    @Autowired
    private CustomInfoService customInfoService;

    public static void main(String[] args) {

        //thb
        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));

        //idr
        System.out.println(AESUtil.encrypt("", "bfa5559109f94c78af615bcf00d52060"));

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


        //sign:bF7YXgBoJnXbonm9S/2eFTceXyrAkS6TiGeV6Z+CyYf02V9p0i8aCt2+CaFAuMbykI0IHsmCJ+mxIq
        // +wYJ37qu0lQ5iMqqQVAy9La4K0TWawHD/gAM5I5WzYnc0D9uNeIG958iVXw1xSLGDyJ7G4URbCJKMgaMh/sIJqrIlA42cCkwoEEZR/dci8
        // +c+x3qqZuFbGep2e7FsLL265jRB8bRcEdQTEH2an6mhvLssx84guCviNy2xIwz691Jy9ZM3gr6CMQI8IeehBFYKk8WG6SyfTbFUut55G1JEKrE9MFiycyB4IYx3JMALjGgSHl6KWHLm4SsV7Dbcp1motfXqS3Q==
    }

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

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

        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(PayOkCallbackEntity callbackEntity, String jsonBody, String payType) throws Exception {
        log.info(String.format("callback orderNo:%s,callback data:%s", callbackEntity.getMerchantOrderId(),
                JSON.toJSONString(callbackEntity)));
        //获取配置
        PayOkPropertyEntity payProperty = getPayProperty(payType, false,
                PayOkPropertyEntity.class);

        //验证传输数据
        boolean flag = validate(jsonBody, payProperty, callbackEntity.getSign());
        if (!flag) {
            return;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
                getFinanceDepositCallbackUpdateEntity(
                        PayConstants.PAYOK_PAY_SUCCESS_STATUS,
                        callbackEntity.getMerchantOrderId(),
                        callbackEntity.getPlatformOrderId(),
                        callbackEntity.getStatus(), callbackEntity);

        balanceCallbackUpdateEntity.setTransformAmount(callbackEntity.getPaidAmount());

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

    }

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

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

        Map<String, Object> params = new HashMap<>(20);
        String datetime = DateUtil.convertDateBetweenTimeZone("GMT+0", balanceTable.getAddTime(), "yyyy-MM-dd'T'HH:mm" +
                ":ss.SSS'Z'");
        params.put("requestTime", datetime);
//        params.put("requestTime", DateUtil.format("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", balanceTable.getAddTime()));

//        params.put("merchantId", propertyEntity.getMerchantId());
        params.put("merchantId", propertyEntity.getMerchantId());
        params.put("countryCode", propertyEntity.getCountryCode());
        params.put("merchantOrderId", String.format("%s_%d", balanceTable.getSerial(), balanceTable.getLogin()));
        params.put("amount", String.format("%.0f",
                balanceTable.getTransformAmount().setScale(0, RoundingMode.HALF_UP).doubleValue()));
        params.put("currency", propertyEntity.getCurrency());
        params.put("notificationUrl", propertyEntity.getCallbackUrl());
        params.put("returnUrl", propertyEntity.getPickupUrl());
        params.put("language", "EN");

        Map<String, String> customerparams = new HashMap<>(20);
        customerparams.put("name", balanceTable.getName());
//        customerparams.put("personalId", customInfoTable.getIdentity());
        customerparams.put("email", customInfoTable.getEmail());
        customerparams.put("phone", customInfoTable.getPhone());
        customerparams.put("deviceId", UUIDUtil.getUUID());
        params.put("customer", customerparams);

        Map<String, String> goodsInfoparams = new HashMap<>(20);
        goodsInfoparams.put("name", "CWG");
        params.put("goodsInfo", goodsInfoparams);

        return payment(propertyEntity, params);
    }

    private String payment(PayOkPropertyEntity propertyEntity, Map<String, Object> params) throws IOException,
            PayValidatedException, ServiceException {

        //转为json
        String data = JSON.toJSONString(params);

        //json去直接加密
        String sign = getSignString(data + "&" + propertyEntity.getOrderCreateUrl(), propertyEntity);

        log.info(String.format("request orderNo:%s,request string:%s,sign:%s",
                params.get("merchantOrderId"),
                data, sign));

        Map<String, String> headers = new HashMap<>(2);
        headers.put("sign", sign);
        headers.put("Content-Type", "application/json");

        log.info(String.format("payok send address:%s,request params:%s,request headers:%s",
                propertyEntity.getBaseUrl() + propertyEntity.getOrderCreateUrl(),
                data, JSON.toJSONString(headers)));

        Connection.Response response = HttpUtil.post(propertyEntity.getBaseUrl() + propertyEntity.getOrderCreateUrl()
                , headers
                , params);
        log.info(String.format("payok Response body:%s", response.body()));

        String responseSign = response.header("sign");

        boolean vl = validate(response.body(), propertyEntity, responseSign);
        if (!vl) {
            log.error("payok request and response body validate is false");

            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }

        JSONObject jsonObject = parseObject(response.body());

        String url = null;
        if ("url".equals(jsonObject.getJSONObject("paymentInfo").getString("type"))) {
            url = jsonObject.getJSONObject("paymentInfo").getString("content");

        } else if ("json".equals(jsonObject.getJSONObject("paymentInfo").getString("type"))) {
            url = jsonObject.getJSONObject("paymentInfo").getJSONObject("content").getString("pay_url");
            if (Strings.isNullOrEmpty(url)) {
                url = jsonObject.getJSONObject("paymentInfo").getJSONObject("content").getJSONObject("app_url").getString("url");
            }

        }

        log.info(String.format("pay request,request orderNo:%s,request url:%s", params.get("merchantOrderId"),
                url));
        return url;
    }

    private String getSignString(String data, PayOkPropertyEntity payProperty) {

        String sign = SignUtil.signSHA256withRSA(payProperty.getPriKey(), data);

        return sign;
    }

    /**
     * 验证回调参数是否被篡改
     *
     * @param data
     * @return
     * @throws ServiceException
     */
    private boolean validate(String data, PayOkPropertyEntity payProperty, String sign) {

        boolean verify = SignUtil.verifySignSHA256withRSA(payProperty.getOkPubKey(), data, sign);

        return verify;

    }

}

