
package com.crm.manager.service.impl;

import com.crm.manager.dao.mapper.SysConfigMapper;
import com.crm.manager.dao.repository.SysConfigRepository;
import com.crm.manager.service.SysConfigService;
import com.crm.rely.backend.core.constant.*;
import com.crm.rely.backend.core.dto.base.PageDto;
import com.crm.rely.backend.core.dto.base.ResultWithPagerDto;
import com.crm.rely.backend.core.dto.system.config.SysConfigSearchDto;
import com.crm.rely.backend.core.entity.system.config.*;
import com.crm.rely.backend.core.entity.system.email.SysEmailSendEntity;
import com.crm.rely.backend.core.pojo.table.SysConfigTable;
import com.crm.rely.backend.core.exception.ServiceException;
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.util.*;

@Service
public class SysConfigServiceImpl implements SysConfigService {

    @Autowired
    private SysConfigRepository sysConfigRepository;

    @Autowired
    private SysConfigMapper sysConfigMapper;

    @Autowired
    private EmailService emailService;

    @Autowired
    private RedisService redisService;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SysConfigAddEntity entity) throws ServiceException {
        existCode(entity.getCode());

        SysConfigTable sysConfigTable = new SysConfigTable();
        BeanUtils.copyProperties(entity, sysConfigTable);
        sysConfigRepository.save(sysConfigTable);
        saveCache(sysConfigTable);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(SysConfigUpdateEntity entity) throws ServiceException {
//        emailService.validateCode(entity.getEmail(), entity.getEmailCode());

        SysConfigTable sysConfigTable;
        if (entity.getId() == null) {
            sysConfigTable = sysConfigRepository.findFirstByCode(entity.getCode());
            if (sysConfigTable != null) {
                entity.setId(sysConfigTable.getId());
            }
        } else {
            sysConfigTable = sysConfigRepository.findFirstByIdAndCode(entity.getId(), entity.getCode());
        }

        if (sysConfigTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }

        BeanUtils.copyProperties(entity, sysConfigTable);
        sysConfigRepository.save(sysConfigTable);

        saveCache(sysConfigTable);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updates(SysConfigUpdateEntitys entitys) throws ServiceException {
        if (entitys == null || entitys.getUpdateData() == null || entitys.getUpdateData().size() <= 0) {
            return;
        }
//        emailService.validateCode(entitys.getEmail(), entitys.getEmailCode());

        List<String> codes = new ArrayList<>(entitys.getUpdateData().size());
        for (BaseSysConfigUpdateEntity entity : entitys.getUpdateData()) {
            codes.add(entity.getCode());
            entity.setModifyIp(entitys.getModifyIp());
            entity.setModifyUser(entitys.getModifyUser());
            entity.setModifyTime(entitys.getModifyTime());
        }
        List<SysConfigTable> sysConfigTables = sysConfigRepository.findAllByCodeIn(codes);
        if (sysConfigTables == null || sysConfigTables.size() <= 0) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        for (BaseSysConfigUpdateEntity entity : entitys.getUpdateData()) {
            for (int i = 0; i < sysConfigTables.size(); i++) {

                SysConfigTable sysConfigTable = sysConfigTables.get(i);
                if (entity.getCode() != null && entity.getCode().equals(sysConfigTable.getCode())) {

                    entity.setId(sysConfigTable.getId());
                    BeanUtils.copyProperties(entity, sysConfigTable);
                }
            }
        }
        sysConfigRepository.save(sysConfigTables);

        saveCache(sysConfigTables);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(SysConfigDeleteEntity entity) throws ServiceException {
        SysConfigTable sysConfigTable = sysConfigRepository.findFirstByIdAndCode(entity.getId(), entity.getCode());

        if (sysConfigTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }

        sysConfigRepository.delete(sysConfigTable);
        redisService.remove(sysConfigTable.getCode());
    }

    @Override
    public ResultWithPagerDto<SysConfigSearchDto> searchPageList(SysConfigSearchEntity entity) throws ServiceException {
        Integer count = sysConfigMapper.countList(entity);
        PageDto pageDto = PageDto.format(entity, count);
        if (count == null || count <= 0) {
            return ResultWithPagerDto.success(pageDto);
        }
        List<SysConfigTable> sysConfigTables = sysConfigMapper.pageList(entity);

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

            throw new ServiceException(Constants.SYSTEM_ERROR);
        }
        List<SysConfigSearchDto> sysConfigSearchDtos = transform(sysConfigTables);

        return ResultWithPagerDto.success(pageDto, sysConfigSearchDtos);
    }

    @Override
    public SysConfigSearchDto searchSingle(SysConfigSingleEntity entity) throws ServiceException {
        SysConfigTable sysConfigTable = sysConfigRepository.getByIdAndCode(entity.getId(), entity.getCode());

        if (sysConfigTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }
        return transform(sysConfigTable);

    }

    @Override
    public SysConfigSearchDto searchSingleByCode(String code) throws ServiceException {
        SysConfigTable sysConfigTable = redisService.getEntity(code, SysConfigTable.class);

        if (sysConfigTable == null) {
            sysConfigTable = sysConfigRepository.getByCode(code);
            if (sysConfigTable == null) {
                throw ServiceException.exception(Constants.INFO_NOT_FOUND);
            } else {
                redisService.save(sysConfigTable.getCode(), sysConfigTable);
            }

        }
        return transform(sysConfigTable);
    }

    @Override
    public List<SysConfigSearchDto> searchSingleByCodes(List<String> codes) throws ServiceException {
        List<SysConfigTable> sysConfigTables = getByCodes(codes);

        return transform(sysConfigTables);
    }

    private List<SysConfigSearchDto> transform(List<SysConfigTable> sysConfigTables) {
        if (sysConfigTables == null || sysConfigTables.size() <= 0) {
            return null;
        }
        List<SysConfigSearchDto> sysConfigSearchDtos = new ArrayList<>(sysConfigTables.size());

        for (SysConfigTable sysConfigTable : sysConfigTables) {
            SysConfigSearchDto sysConfigSearchDto = transform(sysConfigTable);
            sysConfigSearchDtos.add(sysConfigSearchDto);
        }

        return sysConfigSearchDtos;
    }

    private SysConfigSearchDto transform(SysConfigTable sysConfigTable) {
        SysConfigSearchDto sysConfigSearchDto = new SysConfigSearchDto();
        BeanUtils.copyProperties(sysConfigTable, sysConfigSearchDto);
        return sysConfigSearchDto;
    }

    private void existCode(String code) throws ServiceException {
        boolean exist = sysConfigRepository.existsByCode(code);
        if (exist) {
            throw ServiceException.exception(ManagerConstant.CONFIG_CODE_EXIST);
        }
    }

    @Override
    public SysConfigTable getByCode(String code) throws ServiceException {
        SysConfigTable sysConfigTable = redisService.getEntity(code, SysConfigTable.class);
        if (sysConfigTable != null) {
            return sysConfigTable;
        }
        SysConfigTable supplementTable = sysConfigRepository.getByCode(code);
        if (supplementTable == null) {
            throw ServiceException.exception(Constants.INFO_NOT_FOUND);
        }

        saveCache(supplementTable);

        return supplementTable;
    }

    @Override
    public List<SysConfigTable> getByCodes(List<String> codes) throws ServiceException {
        List<SysConfigTable> sysConfigTables = new ArrayList<>(codes.size());
        for (int i = 0; i < codes.size(); ) {
            SysConfigTable sysConfigTable = redisService.getEntity(codes.get(i), SysConfigTable.class);
            if (sysConfigTable != null) {
                sysConfigTables.add(sysConfigTable);
                codes.remove(i);
            } else {
                i++;
            }
        }
        if (codes != null && codes.size() > 0) {
            List<SysConfigTable> supplementTables = sysConfigRepository.getByCodeIn(codes);
            if (sysConfigTables == null || supplementTables.size() <= 0) {
                throw ServiceException.exception(Constants.INFO_NOT_FOUND);
            }

            saveCache(supplementTables);

            sysConfigTables.addAll(supplementTables);
        }
        return sysConfigTables;
    }

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

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

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

    /**
     * 刷新redis config中的数据
     *
     * @throws ServiceException
     */
    @Override
    public void refresh() throws ServiceException {
        List<SysConfigTable> sysConfigTables = sysConfigRepository.getAllByIdIsNotNull();
        saveCache(sysConfigTables);
    }

    @Override
    public void cancel() throws ServiceException {
        List<String> configListKey = redisService.getList(GlobalConfigConstants.CONFIG_LIST, String.class);
        configListKey.add(GlobalConfigConstants.CONFIG_LIST);
        redisService.remove(configListKey);
    }

    private SysEmailSendEntity createUpdateEmailSendEmailSendUpdateEmailCodeEntity(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(GlobalSystemEmailCodeConstants.CONFIG_UPDATE_EMAIL_CODE_SEND);

        sysEmailSendEntity.setMap(map);

        return sysEmailSendEntity;
    }

    private void saveCache(List<SysConfigTable> sysConfigTables) throws ServiceException {
        List<String> configListKey = redisService.getList(GlobalConfigConstants.CONFIG_LIST, String.class);
        sysConfigTables.forEach(v -> {
            try {
                saveCache(v, configListKey);
            } catch (ServiceException e) {
                e.printStackTrace();
            }
        });
    }

    private void saveCache(SysConfigTable sysConfigTable) throws ServiceException {
        saveCache(sysConfigTable, null);
    }

    private void saveCache(SysConfigTable sysConfigTable, List<String> configListKey) throws ServiceException {
        if (configListKey == null) {
            configListKey = redisService.getList(GlobalConfigConstants.CONFIG_LIST, String.class);
        }
        if (configListKey == null) {
            configListKey = new ArrayList<>(10);
        }
        if (!configListKey.contains(sysConfigTable.getCode())) {
            configListKey.add(sysConfigTable.getCode());
        }
        redisService.save(sysConfigTable.getCode(), sysConfigTable);
        redisService.save(GlobalConfigConstants.CONFIG_LIST, configListKey);
    }
}
