package cn.ey.biz.module.system.service.engagement.task;

import cn.ey.biz.common.pojo.PageResult;
import cn.ey.biz.module.system.constant.engagement.TaskTypeConstant;
import cn.ey.biz.module.system.controller.engagement.task.vo.*;
import cn.ey.biz.module.system.convert.engagement.task.EngagementTaskRuleConvert;
import cn.ey.biz.module.system.dal.dataobject.engagement.task.SystemEngagementTaskRuleDO;
import cn.ey.biz.module.system.dal.mapper.engagement.task.SystemEngagementTaskRuleMapper;
import cn.ey.biz.module.system.enums.engagement.DateTypeEnum;
import cn.ey.biz.module.system.enums.engagement.TaskTypeEnum;
import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import static cn.ey.biz.common.exception.util.ServiceExceptionUtil.exception;
import static cn.ey.biz.module.system.enums.ErrorCodeConstants.*;

/**
 * 任务生成规则 Service 实现类
 */
@Service
public class EngagementTaskRuleServiceImpl implements EngagementTaskRuleService {


    @Resource
    private SystemEngagementTaskRuleMapper taskRuleMapper;

    private static final Comparator<SystemEngagementTaskRuleDO> COMPARATOR_ID = Comparator
            .comparing(SystemEngagementTaskRuleDO::getId);

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<Long> createTaskRule(EngagementTaskRuleCreateReqVO reqVO) {
        List<EngagementTaskRuleReqVO> voList = new ArrayList<>();
        List<String> distinctMrCodeList = reqVO.getSmuCode().stream().distinct().collect(Collectors.toList());
        if (reqVO.getSmuCode().size() != distinctMrCodeList.size()) {
            throw exception(TASK_RULE_LIST_REPEAT);
        }
        List<String> taskTypeList = reqVO.getTaskTypeList().stream().map(EngagementTaskRuleTaskTypeReqVO::getTaskType).distinct().collect(Collectors.toList());
        if (reqVO.getTaskTypeList().size() != taskTypeList.size()) {
            throw exception(TASK_RULE_TASK_TYPE_LIST_REPEAT);
        }
        for (String smuCode : reqVO.getSmuCode()) {
            if (smuCode.length() > 16) {
                throw exception(TASK_RULE_TASK_ENTITY_SMU_CODE);
            }
            for (EngagementTaskRuleTaskTypeReqVO taskTypeReqVO : reqVO.getTaskTypeList()) {
                EngagementTaskRuleReqVO engagementTaskRuleReqVO = new EngagementTaskRuleReqVO();
                engagementTaskRuleReqVO.setCountryCode(reqVO.getCountryCode());
                engagementTaskRuleReqVO.setMrCode(reqVO.getMrCode());
                engagementTaskRuleReqVO.setSlCode(reqVO.getSlCode());
                engagementTaskRuleReqVO.setSslCode(reqVO.getSslCode());
                engagementTaskRuleReqVO.setCompetencyCode(reqVO.getCompetencyCode());
                engagementTaskRuleReqVO.setSmuCode(smuCode);
                engagementTaskRuleReqVO.setTaskType(taskTypeReqVO.getTaskType());
                engagementTaskRuleReqVO.setDateType(taskTypeReqVO.getDateType());
                engagementTaskRuleReqVO.setWarningValue(taskTypeReqVO.getWarningValue());
                engagementTaskRuleReqVO.setOverdueDay(taskTypeReqVO.getOverdueDay());
                voList.add(engagementTaskRuleReqVO);
            }
        }
        List<SystemEngagementTaskRuleDO> taskRuleDOS = EngagementTaskRuleConvert.INSTANCE.taskRuleVoToDoConvert(voList);
        //校验任务类型是否存在
        checkTaskRule(taskRuleDOS);
        //校验新增已存在的任务规则
        checkExistList(taskRuleDOS);
        //新增
        taskRuleMapper.insertBatch(taskRuleDOS);

        return taskRuleDOS.stream().map(SystemEngagementTaskRuleDO::getId).collect(Collectors.toList());
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateTaskRule(EngagementTaskRuleReqVO reqVO) {
        EngagementTaskRuleRespVO ruleRespVO = taskRuleMapper.selectById(reqVO.getId());
        if (null == ruleRespVO) {
            throw exception(TASK_RULE_NOT_EXISTS);
        }
        List<EngagementTaskRuleReqVO> voList = new ArrayList<>();
        reqVO.setTaskType(ruleRespVO.getTaskType());
        voList.add(reqVO);
        List<SystemEngagementTaskRuleDO> taskRuleDOS = EngagementTaskRuleConvert.INSTANCE.taskRuleVoToDoConvert(voList);
        List<SystemEngagementTaskRuleDO> toUpdateTaskRuleDOS = checkTaskRule(taskRuleDOS);
        SystemEngagementTaskRuleDO taskRuleDO = toUpdateTaskRuleDOS.get(0);
        taskRuleDO.setDateType(reqVO.getDateType());
        taskRuleDO.setWarningValue(reqVO.getWarningValue());
        taskRuleDO.setOverdueDay(reqVO.getOverdueDay());
        taskRuleDO.setTaskRuleDesc(taskRuleDO.getTaskRuleDesc());
        taskRuleDO.setApplicationDesc(reqVO.getApplicationDesc());
        taskRuleMapper.updateById(taskRuleDO);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteTaskRule(List<Long> ids) {
        for (Long id : ids) {
            EngagementTaskRuleRespVO ruleRespVO = taskRuleMapper.selectById(id);
            if (null == ruleRespVO) {
                throw exception(TASK_RULE_NOT_EXISTS);
            }
        }
        taskRuleMapper.deleteBatchByIds(ids);
    }

    @Override
    public EngagementTaskRuleRespVO getTaskRule(Long id) {
        return taskRuleMapper.selectById(id);
    }

    @Override
    public PageResult<EngagementTaskRuleRespVO> getTaskRulePage(EngagementTaskRuleInfoReqVO reqVO) {
        PageResult<SystemEngagementTaskRuleDO> pageResult = taskRuleMapper.selectPage(reqVO);
        return EngagementTaskRuleConvert.INSTANCE.dtoConvertVoList(pageResult);
    }

    @Override
    public List<SystemEngagementTaskRuleDO> getTaskRuleSimpleList() {
        QueryWrapper<SystemEngagementTaskRuleDO> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("deleted", false);
        queryWrapper.last("limit 1000");
        List<SystemEngagementTaskRuleDO> list = taskRuleMapper.selectList(queryWrapper);
        list.sort(COMPARATOR_ID);
        return list;
    }

    private List<SystemEngagementTaskRuleDO> checkTaskRule(List<SystemEngagementTaskRuleDO> taskRuleAdd) {
        for (SystemEngagementTaskRuleDO t : taskRuleAdd) {
            switch (Objects.requireNonNull(TaskTypeEnum.getByValue(t.getTaskType()))) {
                case AR_OVERDUE:
                    if (StringUtils.isBlank(t.getOverdueDay())) {
                        throw exception(AR_OVERDUE_DAY_NOT_NULL);
                    }
                    //任务规则描述
                    t.setTaskRuleDesc(String.format(TaskTypeConstant.AR_OVERDUE_TASK_RULE_PROMPT, t.getOverdueDay()));
                    t.setOverdueDay(t.getOverdueDay());
                    break;
                case WIP_OVERDUE:
                    if (StringUtils.isBlank(t.getOverdueDay())) {
                        throw exception(WIP_OVERDUE_DAY_NOT_NULL);
                    }
                    t.setTaskRuleDesc(String.format(TaskTypeConstant.WIP_OVERDUE_TASK_RULE_PROMPT, t.getOverdueDay()));
                    t.setOverdueDay(t.getOverdueDay());
                    break;
                case TER_EXCEED_STANDARD:
                    if (t.getWarningValue() == null) {
                        throw exception(TER_EXCEED_STANDARD_NOT_NULL);
                    }
                    t.setTaskRuleDesc(String.format(TaskTypeConstant.TER_EXCEED_STANDARD_PROMPT, t.getWarningValue() + "%"));
                    t.setWarningValue(t.getWarningValue());
                    break;
                case CONTRACT_NOT_FILED:
                    if (t.getDateType() == null || t.getWarningValue() == null) {
                        throw exception(CONTRACT_NOT_FILED_NOT_NULL);
                    }
                    Boolean validByValue = DateTypeEnum.isValidByValue(t.getDateType());
                    if (!validByValue) {
                        throw exception(DATE_TYPE_NOT_EXISTS);
                    }
                    //任务规则描述
                    t.setTaskRuleDesc(String.format(TaskTypeConstant.CONTRACT_NOT_FILED_PROMPT, DateTypeEnum.getNameByValue(t.getDateType()), t.getWarningValue()));
                    t.setDateType(t.getDateType());
                    t.setWarningValue(t.getWarningValue());
                    break;
                case CODE_INACTIVITY:
                    if (t.getWarningValue() == null) {
                        throw exception(CODE_INACTIVITY_NOT_NULL);
                    }
                    //任务规则描述
                    t.setTaskRuleDesc(String.format(TaskTypeConstant.CODE_INACTIVITY_PROMPT, t.getWarningValue()));
                    t.setWarningValue(t.getWarningValue());
                    break;
                default:
                    throw exception(TASK_TYPE_NOT_EXISTS);
            }
        }
        return taskRuleAdd;
    }

    private void checkExistList(List<SystemEngagementTaskRuleDO> taskRuleDOS) {
        List<EngagementTaskRuleRespVO> list = new ArrayList<>();
        for (SystemEngagementTaskRuleDO t : taskRuleDOS) {
            StringBuilder sb = new StringBuilder();
            StringBuilder applicationDesc = sb.append(t.getCountryCode()).append("-")
                    .append(t.getMrCode()).append("-").append(t.getSlCode()).append("-")
                    .append(t.getSslCode()).append("-").append(t.getCompetencyCode()).append("-").append(t.getSmuCode());
            t.setApplicationDesc(applicationDesc.toString());
            t.setDeleted(false);
            t.setVersion(1);
            EngagementTaskRuleRespVO vo = checkIsExist(t.getTaskType(), applicationDesc.toString());
            if (vo != null) {
                list.add(vo);
            }
        }

        if (CollectionUtil.isNotEmpty(list)) {
            throw exception(TASK_RULE_EXISTS, list.stream().map(EngagementTaskRuleRespVO::getApplicationDesc).collect(Collectors.joining(",")));
        }
    }

    private EngagementTaskRuleRespVO checkIsExist(String taskType, String applicationDesc) {
        // 校验任务规则描述与应用对象描述是否已存在
        return taskRuleMapper.selectByTaskRuleDescAndApplicationDesc(taskType, applicationDesc);
    }
}
