package com.docus.server.archivefile.service.impl;

import com.docus.core.util.Func;
import com.docus.core.util.ListUtils;
import com.docus.core.util.property.Setters;
import com.docus.infrastructure.redis.service.IdService;
import com.docus.infrastructure.web.exception.ApiException;
import com.docus.infrastructure.web.exception.ExceptionCode;
import com.docus.infrastructure.web.request.SearchRequest;
import com.docus.infrastructure.web.response.PageResult;
import com.docus.server.archivefile.infrastructure.dao.ITaskConfigDao;
import com.docus.server.archivefile.infrastructure.dao.ITaskConfigRetryLogDao;
import com.docus.server.archivefile.service.ITaskConfigService;
import com.docus.server.entity.TaskConfig;
import com.docus.server.entity.TaskConfigRetryLog;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;

@Service
public class TaskConfigServiceImpl implements ITaskConfigService {
    @Resource
    private ITaskConfigDao taskConfigDao;
    @Resource
    private ITaskConfigRetryLogDao taskConfigRetryLogDao;
    @Resource
    private IdService idService;
    @Resource
    private TrackRetryService trackRetryService;

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateAllPointerDate(String id, Date date) {
        TaskConfig taskConfig = getTaskConfigById(id);
        taskConfig.setAllPointerTime(date);
        updateTaskConfig(taskConfig);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void updateIncPointerDate(String id, Date date) {
        TaskConfig taskConfig = getTaskConfigById(id);
        taskConfig.setIncPointerTime(date);
        updateTaskConfig(taskConfig);
    }

    @Override
    public TaskConfig getTaskConfigById(String taskConfigId) {
        TaskConfig config = taskConfigDao.findById(taskConfigId);
        List<TaskConfigRetryLog> taskConfigRetryLogs = taskConfigRetryLogDao.findBy("messageId", config.getId());
        if (!CollectionUtils.isEmpty(taskConfigRetryLogs)) {
            config.setHaveRetryLog(true);
        }
        return config;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public boolean updateTaskConfig(TaskConfig taskConfig) {
        if (Func.isNull(taskConfig.getId())) {

            validSave(taskConfig.getRetryKey(), taskConfig.getName());

            taskConfig.setId(idService.getDateSeq());

        } else {

            validUpdate(taskConfig.getId(), taskConfig.getName(), taskConfig.getRetryKey());
        }

        return taskConfigDao.saveOrUpdate(taskConfig);
    }

    @Override
    public PageResult<TaskConfig> search(SearchRequest searchRequest) {
        PageResult<TaskConfig> result = searchTaskMessage(searchRequest);

        if (CollectionUtils.isEmpty(result.getList())) {
            return new PageResult<>();
        }

        List<TaskConfigRetryLog> retryLogs = taskConfigRetryLogDao.findBy("messageId", ListUtils.distinctSelect(result.getList(), TaskConfig::getId));
        Map<Long, TaskConfigRetryLog> taskConfigRetryLogMap = ListUtils.toMap(retryLogs, TaskConfigRetryLog::getMessageId);

        Setters.<TaskConfig>instance().list(result.getList()).cycleSetProperties(taskConfig -> {
            if (taskConfigRetryLogMap.containsKey(taskConfig.getId())) {
                taskConfig.setHaveRetryLog(true);
            }
        });

        return result;

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public int deleteTaskConfig(List<Long> ids) {
        return taskConfigDao.deleteByIds(ids);
    }

    public PageResult<TaskConfig> searchTaskMessage(SearchRequest request) {
        return taskConfigDao.searchTaskConfig(request);
    }

    @Override
    public void searchRetry(SearchRequest searchRequest) throws Exception {
        PageResult<TaskConfig> result = searchTaskMessage(searchRequest);
        actionRetry(result.getList());
    }

    @Override
    public void findRetry(List<Long> ids) throws Exception {
        List<TaskConfig> taskMessages = taskConfigDao.findByIds(ids);
        actionRetry(taskMessages);
    }

    private void actionRetry(List<TaskConfig> list) throws Exception {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }

        for (TaskConfig config : list) {
            trackRetryService.doRetryTaskConfig(config);
        }
    }

    private void validUpdate(Long id, String name, String retryKey) {
        int count = taskConfigDao.findByNameAndIdAndKey(id, name, null);

        if (count > 0) {
            throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "任务名称不能重复");
        }

        int keyCount = taskConfigDao.findByNameAndIdAndKey(id, null, retryKey);

        if (keyCount > 0) {
            throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "任务重试键不能重复");
        }
    }

    private void validSave(String retryKey, String name) {
        TaskConfig keyConfig = taskConfigDao.findOneBy("retryKey", retryKey);

        if (Func.notNull(keyConfig)) {
            throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "任务重试键不能重复");
        }

        TaskConfig nameConfig = taskConfigDao.findOneBy("name", name);

        if (Func.notNull(nameConfig)) {
            throw new ApiException(ExceptionCode.ParamIllegal.getCode(), "任务名称不能重复");
        }

    }
}
