package com.crm.pay.service.impl;

import com.alibaba.fastjson.JSON;
import com.crm.pay.dao.repository.SysChannelBankRepository;
import com.crm.pay.dto.ChannelBankRateDto;
import com.crm.pay.entity.ChannelBankRateEntity;
import com.crm.pay.service.FinanceRateService;
import com.crm.pay.service.SysChannelBankService;
import com.crm.pay.service.SysConfigService;
import com.crm.pay.service.SysRemittanceChannelService;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.dto.base.BaseResultDto;
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.dto.sys.remittance.channel.bank.SysChannelBankByChannelCodeDto;
import com.crm.rely.backend.model.dto.sys.remittance.channel.bank.SysChannelBankDto;
import com.crm.rely.backend.model.entity.sys.remittance.channel.bank.SysChannelBankByChannelCodeListEntity;
import com.crm.rely.backend.model.entity.sys.remittance.channel.bank.SysChannelBankByCodeEntity;
import com.crm.rely.backend.model.entity.sys.remittance.channel.bank.SysChannelBankSaveEntity;
import com.crm.rely.backend.model.pojo.table.SysChannelBankTable;
import com.crm.rely.backend.model.pojo.table.SysRemittanceChannelTable;
import org.springframework.beans.BeanUtils;
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.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

@Service
public class SysChannelBankServiceImpl implements SysChannelBankService {

    @Autowired
    private SysChannelBankRepository sysChannelBankRepository;

    @Autowired
    private FinanceRateService financeRateService;

    @Autowired
    private SysRemittanceChannelService sysRemittanceChannelService;
    @Value("${bank.rate.remittanceChannel:CWG_PAY_KEY}")
    private List<String> remittanceChannel;

    @Autowired
    private SysConfigService sysConfigService;

    /**
     * 根据条件拉去所有通道银行(货币类型)列表
     *
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public BaseResultDto<List<SysChannelBankByChannelCodeDto>> getAllByChannelCode(SysChannelBankByChannelCodeListEntity entity) throws Exception {

        List<SysChannelBankTable> sysChannelBankTables;
        if (entity.getBankCodes() != null && entity.getBankCodes().size() > 0) {
            sysChannelBankTables =
                    sysChannelBankRepository.getAllByChannelCodeAndValidAndCountry(entity.getChannelCode(), 1,
                            entity.getCountry(),
                            entity.getBankCodes());
        } else {
            sysChannelBankTables =
                    sysChannelBankRepository.getAllByChannelCodeAndValidAndCountry(entity.getChannelCode(), 1,
                            entity.getCountry());
        }

        if (sysChannelBankTables == null || sysChannelBankTables.size() <= 0) {
            return BaseResultDto.success();
        }
        List<SysChannelBankByChannelCodeDto> sysChannelBankByChannelCodeDtos =
                new ArrayList<>(sysChannelBankTables.size());


        ChannelBankRateDto channelBankRateDto = getChannelBankRateDto(entity.getChannelCode());


        for (SysChannelBankTable sysChannelBankTable : sysChannelBankTables) {
            SysChannelBankByChannelCodeDto sysChannelBankByChannelCodeDto =
                    sysChannelBankTable.transferToDto(SysChannelBankByChannelCodeDto.class);

            if (sysChannelBankByChannelCodeDto.getRate() == null && channelBankRateDto != null) {
                BigDecimal rate = financeRateService.getRate(channelBankRateDto.getCurrency(),
                        sysChannelBankTable.getCurrency()
                        , channelBankRateDto.getType());
                sysChannelBankByChannelCodeDto.setRate(rate);
            }

            sysChannelBankByChannelCodeDtos.add(sysChannelBankByChannelCodeDto);
        }
        return BaseResultDto.success(sysChannelBankByChannelCodeDtos);
    }

    /**
     * 根据条件拉去单个通道银行(货币类型)信息
     *
     * @param entity
     * @return
     * @throws Exception
     */
    @Override
    public BaseResultDto<SysChannelBankByChannelCodeDto> getByCode(SysChannelBankByCodeEntity entity) throws Exception {
        SysChannelBankTable sysChannelBankTable = getByCode(entity.getCode(), entity.getChannelCode());
        if (sysChannelBankTable == null) {
            return BaseResultDto.error(Constants.FAIL);
        }

        SysChannelBankByChannelCodeDto sysChannelBankByChannelCodeDto =
                sysChannelBankTable.transferToDto(SysChannelBankByChannelCodeDto.class);
        return BaseResultDto.success(sysChannelBankByChannelCodeDto);
    }

    @Override
    public SysChannelBankTable getByCode(String code, String channelCode) {
        SysChannelBankTable sysChannelBankTable = sysChannelBankRepository.getFirstByCodeAndChannelCodeAndValid(code,
                channelCode, 1);
        if (sysChannelBankTable == null) {
            return null;
        }

        return sysChannelBankTable;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void save(String channelCode, List<SysChannelBankSaveEntity> entities) throws ServiceException {

        if (entities == null || entities.size() <= 0) {
            List<SysChannelBankTable> sysChannelBankTables = sysChannelBankRepository.findAllByChannelCode(channelCode);
            if (sysChannelBankTables != null && sysChannelBankTables.size() > 0) {
                sysChannelBankRepository.delete(sysChannelBankTables);
            }
            return;
        }

        List<SysChannelBankTable> sysBankSaveTables = new ArrayList<>(entities.size());
        List<SysChannelBankTable> sysChannelBankTables = sysChannelBankRepository.findAllByChannelCode(channelCode);
        List<SysChannelBankTable> sysBankDeleteTables;
        //判断通道code银行是否存在 如果存在 进行判断是否修改和删除 如果不存在则直接进入添加银行实体环节
        if (sysChannelBankTables != null || sysChannelBankTables.size() > 0) {
            sysBankDeleteTables = new ArrayList<>(sysChannelBankTables.size());
            for (SysChannelBankTable sysChannelBankTable : sysChannelBankTables) {
                //标识数据库数据是否需要删除
                boolean isDelete = true;
                int size = entities.size();
                for (int i = 0; i < size; i++) {
                    if (entities.get(i).getId() != null && sysChannelBankTable.getId().equals(entities.get(i).getId())) {
                        BeanUtils.copyProperties(entities.get(i), sysChannelBankTable);
                        sysChannelBankTable.setModifyIp(entities.get(i).getIp());
                        sysChannelBankTable.setModifyTime(entities.get(i).getTime());
                        sysChannelBankTable.setModifyUser(entities.get(i).getUser());
                        sysBankSaveTables.add(sysChannelBankTable);
                        isDelete = false;
                        //移除需要修改的实体 并结束循环
                        entities.remove(i);
                        break;
                    }
                }
                //循环判断中 原数据库数据不在这次修改或者添加范围 则这个记录是需要删除 添加到删除记录中
                if (isDelete) {
                    sysBankDeleteTables.add(sysChannelBankTable);
                }
            }
        } else {
            sysBankDeleteTables = null;
        }
        //剩下的这些为需要添加的实体
        for (SysChannelBankSaveEntity sysChannelBankSaveEntity : entities) {
            sysChannelBankSaveEntity.setId(null);
            SysChannelBankTable sysChannelBankTable = new SysChannelBankTable();
            BeanUtils.copyProperties(sysChannelBankSaveEntity, sysChannelBankTable);
            sysChannelBankTable.setAddIp(sysChannelBankSaveEntity.getIp());
            sysChannelBankTable.setAddTime(sysChannelBankSaveEntity.getTime());
            sysChannelBankTable.setAddUser(sysChannelBankSaveEntity.getUser());
            sysBankSaveTables.add(sysChannelBankTable);
        }

        if (sysBankSaveTables != null && sysBankSaveTables.size() > 0) {
            sysChannelBankRepository.save(sysBankSaveTables);
        }

        if (sysBankDeleteTables != null && sysBankDeleteTables.size() > 0) {
            sysChannelBankRepository.delete(sysBankDeleteTables);
        }
    }

    @Override
    public List<SysChannelBankDto> getByChannelCode(String channelCode) throws ServiceException {
        List<SysChannelBankTable> sysChannelBankTables = sysChannelBankRepository.getAllByChannelCode(channelCode);

        return transform(sysChannelBankTables);
    }

    @Override
    public List<SysChannelBankDto> getByChannelCode(String channelCode, Integer valid) throws ServiceException {
        List<SysChannelBankTable> sysChannelBankTables =
                sysChannelBankRepository.getAllByChannelCodeAndValidOrderBySubIndex(channelCode, valid);

        return transform(sysChannelBankTables);
    }

    @Override
    public List<SysChannelBankDto> getByChannelCodeAndBankCodes(String channelCode, List<String> codes,
                                                                Integer valid) throws ServiceException {
        List<SysChannelBankTable> sysChannelBankTables =
                sysChannelBankRepository.getAllByChannelCodeAndCodeInAndValidOrderBySubIndex(channelCode, codes, valid);

        return transform(sysChannelBankTables);
    }

    @Override
    public List<SysChannelBankDto> getByChannelCodes(List<String> channelCodes) throws ServiceException {
        List<SysChannelBankTable> sysChannelBankTables = sysChannelBankRepository.getAllByChannelCodeIn(channelCodes);

        return transform(sysChannelBankTables);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteByChannelCodes(List<String> channelCodes) throws ServiceException {
        List<SysChannelBankTable> sysChannelBankTables = sysChannelBankRepository.findAllByChannelCodeIn(channelCodes);
        if (sysChannelBankTables != null && sysChannelBankTables.size() > 0) {
            sysChannelBankRepository.delete(sysChannelBankTables);
        }
    }

    private List<SysChannelBankDto> transform(List<SysChannelBankTable> sysChannelBankTables) {

        if (sysChannelBankTables == null || sysChannelBankTables.size() <= 0) {
            return null;
        }

        List<SysChannelBankDto> sysChannelBankDtos = new ArrayList<>(sysChannelBankTables.size());
        sysChannelBankTables.forEach(value -> sysChannelBankDtos.add(transform(value)));

        return sysChannelBankDtos;
    }

    private SysChannelBankDto transform(SysChannelBankTable sysChannelBankTable) {
        SysChannelBankDto sysChannelBankDto = new SysChannelBankDto();
        BeanUtils.copyProperties(sysChannelBankTable, sysChannelBankDto);
        return sysChannelBankDto;
    }

    private ChannelBankRateDto getChannelBankRateDto(String channelCode) throws Exception {
        SysConfigTable sysConfigTable = sysConfigService.getByCode(ConfigConstants.CHANNEL_BANK_RATE);
        if (sysConfigTable == null) {
            return null;
        }
        ChannelBankRateEntity channelBankRateEntity = JSON.parseObject(sysConfigTable.getValue(),
                ChannelBankRateEntity.class);
        if (channelBankRateEntity == null) {
            return null;
        }


        if (channelBankRateEntity.getRemittanceChannels() == null || !channelBankRateEntity.getRemittanceChannels().contains(channelCode)) {

            SysRemittanceChannelTable sysRemittanceChannelTable =
                    sysRemittanceChannelService.getByCode(channelCode, false);

            if (sysRemittanceChannelTable != null) {
                ChannelBankRateDto channelBankRateDto = new ChannelBankRateDto();
                channelBankRateDto.setCurrency(sysRemittanceChannelTable.getCurrency());
                channelBankRateDto.setType(0);
                return channelBankRateDto;
            } else {
                return null;
            }
        }

        if (channelBankRateEntity.getRemitChannels() == null || !channelBankRateEntity.getRemitChannels().contains(channelCode)) {

            ChannelBankRateDto channelBankRateDto = new ChannelBankRateDto();
            channelBankRateDto.setCurrency("USD");
            channelBankRateDto.setType(1);
            return channelBankRateDto;
        }

        return null;
    }
}
