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

import com.alibaba.fastjson.JSON;
import com.crm.pay.entity.FinanceDepositCallbackUpdateEntity;
import com.crm.pay.service.*;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.constant.StatusConstants;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.core.pojo.table.SysConfigTable;
import com.crm.rely.backend.model.constant.ConfigConstants;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.entity.finance.serial.mapping.FinanceDepositSerialMappingEntity;
import com.crm.rely.backend.model.pojo.table.FinanceDepositSerialMappingTable;
import com.crm.rely.backend.model.pojo.table.SysRemitChannelTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import com.crm.rely.backend.util.AESUtil;
import com.google.common.base.Strings;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.List;

/**
 * 通道基础类 提供基础的方法
 *
 * @author houn
 */
public class BasePayServiceImpl extends BaseUploadServiceImpl {

    protected static final String NO_CUT_APART = "NO_CUT";
    @Autowired
    protected FinanceWithdrawService financeWithdrawService;
    @Autowired
    private SysRemittanceChannelService sysRemittanceChannelService;
    @Autowired
    private SysRemitChannelService sysRemitChannelService;
    @Autowired
    private SysConfigService sysConfigService;
    @Autowired
    private FinanceDepositSerialMappingService financeDepositSerialMappingService;

    /**
     * 获取配置数据
     *
     * @return
     * @throws ServiceException
     */
    protected <T> T getPayProperty(String code, Class<T> tClass) throws Exception {

        return getPayProperty(code, true, tClass);
    }

    protected <T> T getPayProperty(String code, boolean valid, Class<T> tClass) throws Exception {

        SysRemittanceChannelTable payChannel = getPayChannel(code, valid);

        T object = getPayProperty(payChannel, tClass);

        return object;
    }

    protected SysRemittanceChannelTable getPayChannel(String code) throws Exception {

        return getPayChannel(code, true);
    }

    /**
     * 获取通道
     *
     * @param code  通道code
     * @param valid 通道是否一定需要启用 true必须启用才能获取到  false 不需要启用就能获取到
     * @return
     * @throws Exception
     */
    protected SysRemittanceChannelTable getPayChannel(String code, boolean valid) throws Exception {

        SysRemittanceChannelTable channel = sysRemittanceChannelService.getSysRemittanceChannelByCode(code, valid);
        if (channel == null || channel.getProperty() == null || channel.getProperty().trim().length() <= 0) {
            throw new ServiceException(PayConstants.FINANCE_DEPOSIT_CHANNEL_NOT_EMPTY);
        }

        return channel;
    }

    protected <T> T getPayProperty(SysRemittanceChannelTable payChannel, Class<T> tClass) throws Exception {
        String property = AESUtil.decrypt(payChannel.getProperty(), this.getPropertyKey(payChannel));
        T object = JSON.parseObject(property, tClass);
        if (object == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }

        return object;
    }

    protected SysRemitChannelTable getWithdrawChannel(String code) throws ServiceException {

        SysRemitChannelTable channel = sysRemitChannelService.getRemitChannelByCode(code);
        if (channel == null || channel.getProperty() == null || channel.getProperty().trim().length() <= 0) {
            throw new ServiceException(PayConstants.FINANCE_WITHDRAW_CHANNEL_NOT_EMPTY);
        }
        return channel;
    }

    protected <T> T getWithdrawPayProperty(SysRemitChannelTable payChannel, Class<T> tClass) throws ServiceException {

        String property = AESUtil.decrypt(payChannel.getProperty(), this.getPropertyKey(payChannel));
        T object = JSON.parseObject(property, tClass);
        if (object == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }

        return object;
    }

    protected <T> T getWithdrawProperty(String code, Class<T> tClass) throws ServiceException {

        SysRemitChannelTable channel = sysRemitChannelService.getRemitChannelByCode(code);
        if (channel == null || channel.getProperty() == null || channel.getProperty().trim().length() <= 0) {
            throw new ServiceException(PayConstants.FINANCE_WITHDRAW_CHANNEL_NOT_EMPTY);
        }
        String property = AESUtil.decrypt(channel.getProperty(), this.getPropertyKey(channel));
        T object = JSON.parseObject(property, tClass);
        if (object == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }

        return object;
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(String success, String orderNo, String transactionId, String status) throws ServiceException {

        return getFinanceDepositCallbackUpdateEntity(success, orderNo, null, transactionId, status);

    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(Integer success,
                                                                                       String orderNo,
                                                                                       String transactionId,
                                                                                       Integer status,
                                                                                       Object callback) throws ServiceException {

        return this.getFinanceDepositCallbackUpdateEntity(success, orderNo, null, transactionId, status, callback);
    }


    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(String success, String orderNo, String middle, String transactionId, String status) throws ServiceException {

        return getFinanceDepositCallbackUpdateEntity(success, orderNo, middle, transactionId, status, null);
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(Integer success,
                                                                                       String orderNo, String middle,
                                                                                       String transactionId,
                                                                                       Integer status,
                                                                                       Object callback) throws ServiceException {

        int statusInt;
        if (success.equals(status)) {
            statusInt = PayConstants.CALLBACE_SUCCESS_STATUS;
        } else {
            statusInt = PayConstants.CALLBACE_FAIL_STATUS;
        }
        return this.getFinanceDepositCallbackUpdateEntity(orderNo, middle, transactionId, statusInt, callback);

    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(String success, String orderNo
            , String middle, String transactionId, String status, Object callback) throws ServiceException {

        int statusInt;
        if (success.equals(status)) {
            statusInt = StatusConstants.PAY_CALLBACK_COMPLETED_STATUS;
        } else {
            statusInt = StatusConstants.PAY_CALLBACK_FAIL_STATUS;
        }
        return getFinanceDepositCallbackUpdateEntity(orderNo, middle, transactionId, statusInt, callback);
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(List<String> success,
                                                                                       String orderNo,
                                                                                       String transactionId,
                                                                                       String status,
                                                                                       Object callback) throws ServiceException {

        return this.getFinanceDepositCallbackUpdateEntity(success, orderNo, null, transactionId, status, callback);
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(List<String> success,
                                                                                       String orderNo, String middle,
                                                                                       String transactionId,
                                                                                       String status) throws ServiceException {

        return this.getFinanceDepositCallbackUpdateEntity(success, orderNo, middle, transactionId, status, null);
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(List<String> success,
                                                                                       String orderNo, String middle,
                                                                                       String transactionId,
                                                                                       String status,
                                                                                       Object callback) throws ServiceException {

        int statusInt;
        if (success.contains(status)) {
            statusInt = PayConstants.CALLBACE_SUCCESS_STATUS;
        } else {
            statusInt = PayConstants.CALLBACE_FAIL_STATUS;
        }
        return this.getFinanceDepositCallbackUpdateEntity(orderNo, middle, transactionId, statusInt, callback);
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(String orderNo, String middle, String transactionId, int status, Object callback) throws ServiceException {
        if (Strings.isNullOrEmpty(middle)) {
            middle = "_";
        }

        FinanceDepositCallbackUpdateEntity balanceCallbackUpdateEntity = new FinanceDepositCallbackUpdateEntity();
        if (Strings.isNullOrEmpty(transactionId)) {
            transactionId = null;
        }
        balanceCallbackUpdateEntity.setChannelSerial(transactionId);

        if (!NO_CUT_APART.equals(middle)) {
            String[] strings = orderNo.split(middle);
            if (strings == null || strings.length < 2) {
                throw new ServiceException(Constants.SYSTEM_ERROR);
            }
            balanceCallbackUpdateEntity.setSerial(strings[0]);
        } else {
            balanceCallbackUpdateEntity.setSerial(orderNo);
        }

        balanceCallbackUpdateEntity.setCallbackStatus(status);
        if (status == PayConstants.CALLBACE_SUCCESS_STATUS) {
            balanceCallbackUpdateEntity.setStatus(PayConstants.MANAGER_COMPLETED_STATUS);
        } else if (status == PayConstants.CALLBACE_FAIL_STATUS) {
            balanceCallbackUpdateEntity.setStatus(PayConstants.MANAGER_FAIL_STATUS);
        }

        balanceCallbackUpdateEntity.setCallbackTime(new Date());
        if (callback != null) {
            balanceCallbackUpdateEntity.setCallbackData(JSON.toJSONString(callback));
        }
        return balanceCallbackUpdateEntity;
    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(String success,
                                                                                       String orderNo,
                                                                                       String transactionId,
                                                                                       String status,
                                                                                       Object callback) throws ServiceException {

        return this.getFinanceDepositCallbackUpdateEntity(success, orderNo, null, transactionId, status, callback);

    }

    protected FinanceDepositCallbackUpdateEntity getFinanceDepositCallbackUpdateEntity(String orderNo,
                                                                                       String transactionId,
                                                                                       int status, Object callback) throws ServiceException {
        return this.getFinanceDepositCallbackUpdateEntity(orderNo, "_", transactionId, status, callback);
    }

    private String getPropertyKey(SysRemittanceChannelTable payChannel) throws ServiceException {
        if (!Strings.isNullOrEmpty(payChannel.getPk())) {
            return payChannel.getPk();
        }
        SysConfigTable table = sysConfigService.getByCode(ConfigConstants.FINANCE_PROPERTY_KEY);
        if (table == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return table.getValue();
    }

    private String getPropertyKey(SysRemitChannelTable payChannel) throws ServiceException {
        if (!Strings.isNullOrEmpty(payChannel.getPk())) {
            return payChannel.getPk();
        }
        SysConfigTable table = sysConfigService.getByCode(ConfigConstants.FINANCE_PROPERTY_KEY);
        if (table == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return table.getValue();
    }

    protected FinanceDepositSerialMappingTable getById(String reNo, String payType) throws ServiceException {
        if (Strings.isNullOrEmpty(reNo)) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }

        String idString = reNo.split("_")[0];

        Long id = Long.parseLong(idString);
        FinanceDepositSerialMappingTable financeDepositSerialMappingTable =
                financeDepositSerialMappingService.getById(id, payType);
        if (financeDepositSerialMappingTable == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return financeDepositSerialMappingTable;

    }

    protected FinanceDepositSerialMappingTable saveMapping(String serial, String payType) throws ServiceException {
        FinanceDepositSerialMappingEntity entity = new FinanceDepositSerialMappingEntity();

        entity.setPayType(payType);
        entity.setDepositSerial(serial);
        FinanceDepositSerialMappingTable financeDepositSerialMappingTable =
                financeDepositSerialMappingService.save(entity);
        if (financeDepositSerialMappingTable == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        return financeDepositSerialMappingTable;

    }


}
