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

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.crm.pay.entity.callback.hyper.hashing.HyperHashingCallbackEntity;
import com.crm.pay.entity.property.HyperHashingPropertyEntity;
import com.crm.pay.service.CustomInfoService;
import com.crm.pay.service.FinanceDepositService;
import com.crm.pay.service.HyperHashingService;
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.FinanceDepositTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
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 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.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @program:
 * @description:
 * @author: houn
 * @create: 2024-06-12 11:45
 */
@Slf4j
@Service
public class HyperHashingServiceImpl extends BasePayServiceImpl implements HyperHashingService {
    @Autowired
    private FinanceDepositService financeDepositService;

    @Autowired
    private CustomInfoService customInfoService;

    public static void main(String[] args) throws Exception {
        System.out.println(AESUtil.decrypt("",
                "bfa5559109f94c78af615bcf00d52060"));

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

    }

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

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

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

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

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

        JSONObject jsonObject = JSON.parseObject(jsoncfn);
        HyperHashingCallbackEntity callbackEntity = JSON.parseObject(jsoncfn, HyperHashingCallbackEntity.class);
        String orderNo = null;
        if (callbackEntity != null && callbackEntity.getData() != null) {

            orderNo = callbackEntity.getData().getExternalReference();
        }

        log.info(String.format("callback orderNo:%s,callback data:%s",
                orderNo, jsoncfn));


        HyperHashingPropertyEntity propertyEntity = getPayProperty(PayConstants.HYPER_HASHING_PAY_TYPE, false,
                HyperHashingPropertyEntity.class);
        if (validate(orderNo, jsonObject.getString("data"), callbackEntity.getHash(), propertyEntity)) {
            throw new ServiceException("fail");
        }
        Integer callbackStatus;
        if (PayConstants.HYPER_HASHING_SUCCESS_STATUS.equals(callbackEntity.getStatusCode())) {
            callbackStatus = 1;
        } else {
            callbackStatus = 2;
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity = new FinanceDepositCallbackUpdateEntity();

        balanceCallbackUpdateEntity.setCallbackStatus(callbackStatus);
        balanceCallbackUpdateEntity.setSerial(orderNo.split("L")[0]);
        balanceCallbackUpdateEntity.setChannelSerial(callbackEntity.getData().getTxid());
        balanceCallbackUpdateEntity.setTicket(callbackEntity.getData().getTxid());
        balanceCallbackUpdateEntity.setCallbackTime(new Date());
        balanceCallbackUpdateEntity.setCallbackData(JSON.toJSONString(callbackEntity));
        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getData().getBalance()));

//        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity =
//                getFinanceDepositCallbackUpdateEntity(PayConstants.HYPER_HASHING_SUCCESS_STATUS,
//                        orderNo,
//                        callbackEntity.getData().getTxid(),
//                        callbackEntity.getStatusCode(), callbackEntity);

        balanceCallbackUpdateEntity.setTransformAmount(new BigDecimal(callbackEntity.getData().getBalance()));
//        /**
//         * 更新数据
//         */
        financeDepositService.updateCallback(balanceCallbackUpdateEntity);
    }

    /**
     * 获取支付url
     *
     * @param financeDepositTable
     * @return
     * @throws ServiceException
     */
    private String getUrl(HyperHashingPropertyEntity property, FinanceDepositTable financeDepositTable) throws Exception {

        String orderNo = financeDepositTable.getSerial() + "L" + financeDepositTable.getLogin();
        Map<String, Object> data = new HashMap<>();
        data.put("symbol", "tron");
        data.put("timestamp", System.currentTimeMillis() / 1000L);
        data.put("externalReference", orderNo);

        String dataStr = JSON.toJSONString(data);

        Map<String, Object> params = new HashMap<>();
        params.put("merchant_id", property.getMerchantId());
        params.put("hash", getSign(orderNo, property, dataStr));
        params.put("data", data);

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

        header.put("Content-Type", "application/json;charset=UTF-8");

        String payUrl = property.getBaseUrl();

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

        log.info(String.format("send rul:%s,header:%s,params:%s,body:%s", payUrl,
                JSON.toJSONString(header), JSON.toJSONString(params), response.body()));

        JSONObject jsonResponse = JSON.parseObject(response.body());
        if (!jsonResponse.getString("statusCode").equals("200")) {
            throw new ServiceException(jsonResponse.getString("msg"));
        }

        String address = jsonResponse.getString("address");

        String url = String.format(property.getPaymentUrl(), address, property.getSuccessUrl(),
                property.getReturnUrl(), financeDepositTable.getCurrency(),
                String.format("%.4f", financeDepositTable.getAmount().doubleValue()), property.getCurrencyType());
        financeDepositTable.setChannelSerial(address);
        log.info(String.format("orderNo:%s,url:%s", orderNo, url));
        return url;
    }

    private boolean validate(String order, String data, String hash, HyperHashingPropertyEntity payProperty) throws Exception {
        String sign = getSign(order, payProperty, data);
        return hash.equals(sign);
    }

    private String getSign(String order, HyperHashingPropertyEntity propertyEntity, String data) throws Exception {
        String sign = HAMCSHAUtil.sha512HMACBase64(data, propertyEntity.getKey());

        log.info(String.format("orderNo:%s,sign string:%s,sign:%s", order, data, sign));

        return sign;
    }

}
