package com.crm.manager.service.impl;

import com.crm.manager.dao.mapper.FinanceRateMapper;
import com.crm.manager.dao.repository.FinanceRateRepository;
import com.crm.manager.service.FinanceRateService;
import com.crm.rely.backend.core.constant.Constants;
import com.crm.rely.backend.core.constant.EmailSendEnum;
import com.crm.rely.backend.core.constant.MapConstants;
import com.crm.rely.backend.core.dto.base.BaseResultDto;
import com.crm.rely.backend.core.entity.system.config.SendUpdateEmailCodeEntity;
import com.crm.rely.backend.core.entity.system.email.SysEmailSendEntity;
import com.crm.rely.backend.core.exception.ServiceException;
import com.crm.rely.backend.model.constant.PayConstants;
import com.crm.rely.backend.model.dto.finance.rate.FinanceRateSearchDto;
import com.crm.rely.backend.model.entity.finance.rate.*;
import com.crm.rely.backend.model.pojo.table.FinanceRateTable;
import com.crm.rely.backend.service.EmailService;
import com.crm.rely.backend.service.RedisService;
import com.crm.rely.backend.util.DateUtil;
import com.crm.rely.backend.util.GetRandom;
import org.springframework.beans.BeanUtils;
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.*;

@Service
public class FinanceRateServiceImpl implements FinanceRateService {


    @Autowired
    private FinanceRateRepository financeRateRepository;

    @Autowired
    private FinanceRateMapper financeRateMapper;

    @Autowired
    private EmailService emailService;

    @Autowired
    private RedisService redisService;


    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void add(FinanceRateAddEntity entity) throws ServiceException {

//        emailService.validateCode(entity.getEmail(), entity.getEmailCode());

        existCurrency(entity.getCurrency(), entity.getTransformCurrency(), entity.getType());

        FinanceRateTable financeRateTable = new FinanceRateTable();
        BeanUtils.copyProperties(entity, financeRateTable);
        financeRateRepository.save(financeRateTable);

        redisService.save(entity.getCurrency() + entity.getTransformCurrency() + entity.getType(), entity.getRate(),
                60 * 60 * 1000);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void update(FinanceRateUpdateEntity entity) throws ServiceException {

//        emailService.validateCode(entity.getEmail(), entity.getEmailCode());

        FinanceRateTable financeRateTable = financeRateRepository.findFirstById(entity.getId());

        if (!entity.getCurrency().equals(financeRateTable.getCurrency()) ||
                !entity.getTransformCurrency().equals(financeRateTable.getTransformCurrency()) ||
                !entity.getType().equals(financeRateTable.getType())) {
            existCurrency(entity.getCurrency(), entity.getTransformCurrency(), entity.getType());
        }
        BeanUtils.copyProperties(entity, financeRateTable);
        financeRateRepository.save(financeRateTable);

        redisService.save(entity.getCurrency() + entity.getTransformCurrency() + entity.getType(), entity.getRate(),
                60 * 60 * 1000);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void save(FinanceRateBatchUpdateEntity entity, List<FinanceRateUpdateEntity> entitys) throws ServiceException {

//        emailService.validateCode(entity.getEmail(), entity.getEmailCode());


        List<FinanceRateTable> financeRateTables = financeRateRepository.findAllByType(entity.getType());

        if (entitys == null || entitys.size() <= 0) {
            financeRateRepository.delete(financeRateTables);
        }
        Map<String, String> mapCurrency = new HashMap<>(financeRateTables.size());
        Map<Long, FinanceRateTable> mapId = new HashMap<>(financeRateTables.size());
        for (FinanceRateTable financeRateTable : financeRateTables) {

            mapId.put(financeRateTable.getId(), financeRateTable);
        }

        List<FinanceRateTable> financeRateSaveTables = new ArrayList<>();
        if (entitys != null) {
            for (FinanceRateUpdateEntity financeRateUpdateEntity : entitys) {

                String key =
                        financeRateUpdateEntity.getCurrency() + "/" + financeRateUpdateEntity.getTransformCurrency();
                if (mapCurrency.containsKey(key)) {
                    throw ServiceException.exception(Constants.CURRENCY_EXIST_ERROR);
                } else {
                    mapCurrency.put(key, key);
                }
                FinanceRateTable financeRateTable;
                if (financeRateUpdateEntity.getId() != null) {
                    financeRateTable = mapId.get(financeRateUpdateEntity.getId());
                    if (financeRateTable == null) {
                        throw new ServiceException(Constants.INFO_NOT_FOUND);
                    }

                    BeanUtils.copyProperties(financeRateUpdateEntity, financeRateTable);

                    mapId.remove(financeRateTable.getId());
                } else {
                    financeRateTable = new FinanceRateTable();
                    BeanUtils.copyProperties(financeRateUpdateEntity, financeRateTable);
                    financeRateTable.setAddIp(financeRateUpdateEntity.getModifyIp());
                    financeRateTable.setAddUser(financeRateUpdateEntity.getModifyUser());
                    financeRateTable.setAddTime(financeRateUpdateEntity.getModifyTime());
                    financeRateTable.setModifyTime(null);
                    financeRateTable.setModifyIp(null);
                    financeRateTable.setModifyUser(null);


                }
                financeRateSaveTables.add(financeRateTable);
            }
        }


        if (financeRateSaveTables != null && !financeRateSaveTables.isEmpty()) {
            financeRateRepository.save(financeRateSaveTables);
        }

        if (!mapId.isEmpty()) {
            Collection<FinanceRateTable> financeRateDeleteTables = mapId.values();
            financeRateRepository.delete(financeRateDeleteTables);
        }

        for (FinanceRateTable financeRateTable : financeRateTables) {

            redisService.save(financeRateTable.getCurrency() + financeRateTable.getTransformCurrency() + financeRateTable.getType(), financeRateTable.getRate(),
                    60 * 60 * 1000);
        }

    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void delete(FinanceRateDeleteEntity entity) throws ServiceException {

//        emailService.validateCode(entity.getEmail(), entity.getEmailCode());

        if (entity == null || entity.getIds().size() <= 0) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        List<FinanceRateTable> financeRateTables = financeRateRepository.findAllByIdIn(entity.getIds());
        if (financeRateTables == null || financeRateTables.size() <= 0) {
            return;
        }
        financeRateRepository.delete(financeRateTables);

        for (FinanceRateTable financeRateTable : financeRateTables) {

            redisService.remove(financeRateTable.getCurrency() + financeRateTable.getTransformCurrency() + financeRateTable.getType());
        }
    }

//    @Override
//    public ResultWithPagerDto<FinanceRateSearchDto> searchPageList(FinanceRateSearchListEntity entity) throws
//    ServiceException {
//        Integer count = financeRateMapper.countList(entity);
//        PageDto pageDto = PageDto.format(entity, count);
//        if (count == null || count <= 0) {
//            return ResultWithPagerDto.success(pageDto);
//        }
//        List<FinanceRateTable> financeRateTables = financeRateMapper.pageList(entity);
//
//        if (financeRateTables == null || financeRateTables.size() <= 0) {
//
//            throw new ServiceException(Constants.SYSTEM_ERROR);
//        }
//        List<FinanceRateSearchDto> financeRateSearchDtos = new ArrayList<>(financeRateTables.size());
//
//        for (FinanceRateTable financeRateTable : financeRateTables) {
//            FinanceRateSearchDto rateSearchDto = transform(financeRateTable);
//            financeRateSearchDtos.add(rateSearchDto);
//        }
//
//        return ResultWithPagerDto.success(pageDto, financeRateSearchDtos);
//    }

    @Override
    public BaseResultDto searchList(FinanceRateSearchListEntity entity) throws ServiceException {

        List<FinanceRateTable> financeRateTables = financeRateMapper.searchList(entity);

        if (financeRateTables == null || financeRateTables.size() <= 0) {

            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        List<FinanceRateSearchDto> financeRateSearchDtos = new ArrayList<>(financeRateTables.size());

        for (FinanceRateTable financeRateTable : financeRateTables) {
            FinanceRateSearchDto rateSearchDto = transform(financeRateTable);
            financeRateSearchDtos.add(rateSearchDto);
        }

        return BaseResultDto.success(financeRateSearchDtos);
    }

    @Override
    public FinanceRateSearchDto searchSingle(Long id) throws ServiceException {
        FinanceRateTable financeRateTable = financeRateRepository.getFirstById(id);
        if (financeRateTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        return transform(financeRateTable);
    }

    @Override
    public void sendEmailCode(SendUpdateEmailCodeEntity entity) throws ServiceException {

        //构建实体
        SysEmailSendEntity sysEmailSendEntity = createSendEmailCodeEntity(entity);

        //发送收据
        emailService.sendCode(sysEmailSendEntity, sysEmailSendEntity.getMap().get(MapConstants.CODE));
    }

    private SysEmailSendEntity createSendEmailCodeEntity(SendUpdateEmailCodeEntity entity) {
        SysEmailSendEntity sysEmailSendEntity = new SysEmailSendEntity();

        Map<String, String> map = new HashMap<>(2);
        String code = GetRandom.getRandom(6);
        map.put(MapConstants.CODE, code);
        Date time = DateUtil.operationMinute(new Date(), Constants.EMAIL_VALIDATECODE_TIME);
        map.put(MapConstants.EXPIRE_TIME, DateUtil.formatTime(time));
        map.put(MapConstants.DATE_TIME, DateUtil.formatTime());

        sysEmailSendEntity.setAddIp(entity.getIp());
        sysEmailSendEntity.setAddTime(entity.getTime());

        sysEmailSendEntity.setUsers(entity.getEmail());
        sysEmailSendEntity.setEmailSendEnum(EmailSendEnum.UPDATE_CONFIG_EMAIL_CODE);

        //sysEmailSendEntity.setTemplateName(SystemEmailCodeConstants.CONFIG_UPDATE_EMAIL_CODE_SEND);

        sysEmailSendEntity.setMap(map);

        return sysEmailSendEntity;
    }

    private void existCurrency(String currency, String transformCurrency, Integer type) throws ServiceException {
        boolean bl = financeRateRepository.existsByCurrencyAndTransformCurrencyAndType(currency, transformCurrency,
                type);
        if (bl) {
            throw ServiceException.exception(Constants.CURRENCY_EXIST_ERROR);
        }
    }

    private FinanceRateSearchDto transform(FinanceRateTable financeRateTable) {
        FinanceRateSearchDto financeRateSearchDto = new FinanceRateSearchDto();
        BeanUtils.copyProperties(financeRateTable, financeRateSearchDto);
        return financeRateSearchDto;
    }

    @Override
    public BigDecimal getRate(String currency, String transformCurrency, Integer type) throws ServiceException {
        if (type == null) {
            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        BigDecimal rate = null;

        if (currency.equals(transformCurrency)) {
            return BigDecimal.ONE;
        }

        //先用转化货币和货币进行获取
        FinanceRateTable financeRateTable = financeRateRepository.getByTypeAndCurrencyAndTransformCurrency(type, transformCurrency, currency);
        //如果不存在 则根据货币和转换货币获取汇率
        if (financeRateTable == null) {
            financeRateTable = financeRateRepository.getByTypeAndCurrencyAndTransformCurrency(type, currency, transformCurrency);
            //如果不存在 则表示当前系统未设置此货币汇率
            if (financeRateTable == null) {
                if (type != null && type.equals(0)) {
                    throw new ServiceException(PayConstants.FINANCE_DEPOSIT_RATE_NOT_EMPTY);
                } else {
                    throw new ServiceException(PayConstants.FINANCE_WITHDRAW_RATE_NOT_EMPTY);
                }
            }
            int roundingMode = 1;
            if (type != null) {
                if (type.equals(0)) {
                    roundingMode = 0;
                } else if (type.equals(1)) {
                    roundingMode = 1;
                }
            }
            rate = BigDecimal.ONE.divide(financeRateTable.getRate(), 10, roundingMode);
        } else {
            rate = financeRateTable.getRate();
        }
        return rate;
    }

    public BigDecimal getRateAmount(String currency, String transformCurrency, Integer type, BigDecimal amount) throws ServiceException {

        if (amount == null) {
            throw ServiceException.exception(Constants.SYSTEM_ERROR);
        }
        BigDecimal rate = getRate(currency, transformCurrency, type);

        return amount.multiply(rate);
    }

}
