package com.ruoyi.sim.service.impl;

import java.util.*;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.sim.domain.Fault;
import com.ruoyi.sim.domain.TaskFault;
import com.ruoyi.sim.domain.vo.FaultTreeVo;
import com.ruoyi.sim.domain.vo.TaskCUVo;
import com.ruoyi.sim.domain.vo.TaskVo;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.ruoyi.sim.mapper.TaskMapper;
import com.ruoyi.sim.domain.Task;
import org.springframework.transaction.annotation.Transactional;

/**
 * 任务Service业务层处理
 *
 * @author tom
 * @date 2024-12-13
 */
@Service
public class TaskService {

    private static final Logger l = LoggerFactory.getLogger(TaskService.class);

    @Autowired
    private TaskMapper taskMapper;
    @Autowired
    private FaultService faultService;
    @Autowired
    private TaskFaultService taskFaultService;
    @Autowired
    private SimService simService;

    /**
     * 查询任务
     *
     * @param taskId 任务主键
     * @return 任务
     */
    public AjaxResult selectTaskByTaskId(Long taskId) {
        // check
        if (taskId == null) {
            return AjaxResult.error("taskId is null");
        }
        Task t = taskMapper.selectTaskByTaskId(taskId);
        if (t == null) {
            return AjaxResult.error("task is null");
        }
        //
        TaskVo vo = new TaskVo();
        String simType = t.getSimType();
        BeanUtils.copyProperties(t, vo);
        // 查询获得数据结构。
        List<FaultTreeVo> listStyleT = faultService.listAllListTreeStyleBySimType(simType);
        // 变成扁平list
        List<FaultTreeVo> listStyleF = FaultService.flatten(listStyleT);
        for (FaultTreeVo o : listStyleF) {
            if (o == null) {
                continue;
            }
            if (Fault.Type.REAL_GZBW.equals(o.getFaultType())) {
                TaskFault tf = o.getTaskFault();
                TaskFault tfQ = taskFaultService.selectUniqueTaskFault(taskId, tf.getFaultId());
                // 存在就设置上数据库中TaskFault值。
                if (tfQ != null) {
                    o.setTaskFault(tfQ);
                }
            }
        }
        // 变成树list
        vo.setSelectedData(FaultService.toTree(listStyleF, Fault.ROOT_FAULT_ID));
        // 故障现象
        vo.setCountGZXX(getCountGZXX(taskId));
        // 故障部位
        vo.setCountGZBW(getCountGZBW(taskId));
        //
        return AjaxResult.success(vo);
    }

    /**
     * 查询任务列表
     *
     * @param q 任务
     * @return 任务
     */
    public List<TaskVo> list(Task q) {
        if (q == null) {
            return Collections.emptyList();
        }
        List<Task> listT = taskMapper.selectTaskList(q);
        List<TaskVo> listVo = new ArrayList<>(listT.size());
        listT.forEach(t -> {
            TaskVo vo = new TaskVo();
            BeanUtils.copyProperties(t, vo);
            // 故障现象
            vo.setCountGZXX(getCountGZXX(t.getTaskId()));
            // 故障部位
            vo.setCountGZBW(getCountGZBW(t.getTaskId()));
            listVo.add(vo);
        });
        return listVo;
    }

    public int getCountGZXX(long taskId) {
        return faultService.countType1ByType3(
                taskFaultService.toFaultList(
                        taskFaultService.listYesByFaultType(taskId, Fault.Type.REAL_GZBW)
                )
        );
    }

    public int getCountGZBW(long taskId) {
        return taskFaultService.countYesByFaultType(taskId, Fault.Type.REAL_GZBW);
    }

    @Transactional()
    public AjaxResult insertOrUpdateTaskByTeacher(TaskCUVo v) {
        String simType = v.getSimType();
        String[] faultIds = v.getFaultIds();
        l.info("simType = {}", simType);
        // check
        AjaxResult arE1 = check(simType, faultIds);
        if (arE1.isError()) {
            return arE1;
        }
        Set<String> hashSet = new HashSet<>(Arrays.asList(faultIds));
        l.info("hashSet = {}", hashSet);
        TaskVo tv = buildBlankTaskVo(simType);
        // 查询获得数据结构。
        List<FaultTreeVo> listStyleT = tv.getSelectedData();
        // 变成扁平list
        List<FaultTreeVo> listStyleF = FaultService.flatten(listStyleT);
        listStyleF
                .stream()
                .filter(vo -> hashSet.contains(vo.getFaultId()))
                .forEach(vo -> vo.getTaskFault().setFlag(TaskFault.Flag.YES));
        if (v.getTaskId() == null || v.getTaskId() == 0) {
            tv.setTaskId(null);
        } else {
            tv.setTaskId(v.getTaskId());
        }
        tv.setName(v.getName());
        tv.setSimType(v.getSimType());
        l.info("listStyleF.size = {}", listStyleF.size());
        // 变回tree
        tv.setSelectedData(FaultService.toTree(listStyleF, Fault.ROOT_FAULT_ID));
        AjaxResult arE2 = null;
        if (v.getTaskId() == null || v.getTaskId() == 0) {
            arE2 = insertTaskByTeacher(tv);
        } else {
            arE2 = updateTaskByTeacher(tv);
        }
        if (arE2 == null || arE2.isError()) {
            return arE2;
        }
        return AjaxResult.success();
    }

    public AjaxResult check(String simType, String[] faultIds) {
        for (String faultId : faultIds) {
            if (!faultService.isType3(faultId)) {
                return AjaxResult.error("faultId not TYPE_GZBW!");
            }
        }
        if (!faultService.isExist(simType, faultIds)) {
            return AjaxResult.error("faultId not exist!");
        }
        return AjaxResult.success();
    }

    /**
     * 新增任务
     *
     * @param tv 任务
     * @return 结果
     * todo:事务有问题。
     */
    @Transactional()
    public AjaxResult insertTaskByTeacher(TaskVo tv) {
        l.info("insertTaskByTeacher {}", tv);
        // check
        AjaxResult arE1 = checkAddOrEdit(tv);
        if (arE1.isError()) {
            return arE1;
        }
        //
        tv.setCreateByUserId(SecurityUtils.getUserId());
        tv.setCreateBy(SecurityUtils.getUsername());
        tv.setCreateTime(DateUtils.getNowDate());
        tv.setUpdateBy(SecurityUtils.getUsername());
        tv.setUpdateTime(DateUtils.getNowDate());
        // do.
        // id新增一定要null。
        tv.setTaskId(null);
        taskMapper.insertTask(tv);
        // do ref.
        AjaxResult arRef = dealRef(tv);
        if (arRef.isError()) {
            return arRef;
        }
        return AjaxResult.success();
    }

    /**
     * 修改任务
     *
     * @param tv 任务
     * @return 结果
     */
    public AjaxResult updateTaskByTeacher(TaskVo tv) {
        l.info("updateTaskByTeacher " + tv);
        // check
        AjaxResult arE1 = checkAddOrEdit(tv);
        if (arE1.isError()) {
            return arE1;
        }
        // check taskId
        {
            Task tQ = taskMapper.selectTaskByTaskId(tv.getTaskId());
            if (tQ == null) {
                return AjaxResult.error("taskId not exist!");
            }
        }
        //
        tv.setCreateByUserId(SecurityUtils.getUserId());
        tv.setCreateBy(SecurityUtils.getUsername());
        tv.setCreateTime(DateUtils.getNowDate());
        tv.setUpdateBy(SecurityUtils.getUsername());
        tv.setUpdateTime(DateUtils.getNowDate());
        // do.
        if (tv.getTaskId() == null || tv.getTaskId() == 0) {
            return AjaxResult.error("taskId not exist!");
        }
        taskMapper.updateTask(tv);
        // do ref.
        AjaxResult arE2 = dealRef(tv);
        if (arE2.isError()) {
            return arE2;
        }
        return AjaxResult.success();
    }

    public AjaxResult checkAddOrEdit(TaskVo tv) {
        if (tv == null) {
            return AjaxResult.error("TaskVo empty!");
        }
        if (!simService.checkSimTypeOk(tv.getSimType())) {
            return AjaxResult.error("simType value error!");
        }
        if (!Task.Type.TEACHER_ADD.equals(tv.getTaskType())) {
            return AjaxResult.error("taskType value error!");
        }
        if (StringUtils.isEmpty(tv.getName())) {
            return AjaxResult.error("name isEmpty!");
        }
        return AjaxResult.success();
    }

    public boolean exist(Long taskId) {
        return (selectTaskByTaskId(taskId) != null);
    }


    /**
     * 处理关联数据。
     *
     * @param tv
     */
    public AjaxResult dealRef(TaskVo tv) {
        List<FaultTreeVo> selectedData = tv.getSelectedData();
        if (selectedData == null) {
            return AjaxResult.error("selectedData null!");
        }
        List<FaultTreeVo> list = FaultService.flatten(selectedData);
        dealRef(tv.getTaskId(), list);
        return AjaxResult.success();
    }

    /**
     * @param flatten 扁平list
     * @return
     */
    public AjaxResult dealRef(Long taskId, List<FaultTreeVo> flatten) {
        for (FaultTreeVo ftv : flatten) {
            if (ftv == null) {
                continue;
            }
            // 仅仅处理故障部位。
            if (!Fault.Type.REAL_GZBW.equals(ftv.getFaultType())) {
                continue;
            }
            TaskFault tf = ftv.getTaskFault();
            // check
            if (tf == null) {
                return AjaxResult.error("TaskFault empty!");
            }
            String flag = tf.getFlag();
            if (StringUtils.isEmpty(flag)) {
                return AjaxResult.error("flag empty!");
            }
            if (!TaskFault.Flag.YES.equals(flag) &&
                    !TaskFault.Flag.NO.equals(flag) &&
                    !TaskFault.Flag.UNKNOWN.equals(flag)) {
                return AjaxResult.error("flag must YES or NO,UNKNOWN!");
            }
            // todo:选中数量限制

            // 故障部位冲突 暂时没有故障部位冲突。
            // UNKNOWN 作为 NO 插入或修改数据。
            // 处理flag。
            if (TaskFault.Flag.UNKNOWN.equals(flag)) {
                tf.setFlag(TaskFault.Flag.NO);
            }
            tf.setTaskId(taskId);
            //
            TaskFault tfQ = taskFaultService.selectUniqueTaskFault(taskId, tf.getFaultId());
            if (tfQ == null) {
                taskFaultService.insertTaskFault(taskId, tf.getFaultId(), tf.getFlag());
            } else {
                tfQ.setFlag(tf.getFlag());
                taskFaultService.updateTaskFault(tfQ);
            }
        }
        return AjaxResult.success();
    }

    /**
     * 批量删除任务
     *
     * @param ids 需要删除的任务主键
     * @return 结果
     */
    @Transactional
    public AjaxResult deleteTaskByTaskIds(Long[] ids) {
        if (ids == null || ids.length == 0) {
            return AjaxResult.error("taskIds null!");
        }
        for (Long tId : ids) {
            taskMapper.deleteTaskByTaskId(tId);
            taskFaultService.deleteTaskFaultByTaskId(tId);
        }
        return AjaxResult.success();
    }

    /**
     * 删除任务信息
     *
     * @param taskId 任务主键
     * @return 结果
     */
    public int deleteTaskByTaskId(Long taskId) {
        return taskMapper.deleteTaskByTaskId(taskId);
    }


    /**
     * 为了新建Task，返回一个带tree结构的任务详细信息。
     *
     * @return 任务
     */
    public AjaxResult getInfoForAdd(final String simType) {
        // check
        if (StringUtils.isEmpty(simType)) {
            return AjaxResult.error("simType empty!");
        }
        if (!simService.checkSimTypeOk(simType)) {
            return AjaxResult.error("simType value error!");
        }
        return AjaxResult.success(buildBlankTaskVo(simType));
    }

    /**
     * @param simType
     * @return tree style
     */
    public TaskVo buildBlankTaskVo(final String simType) {
        List<FaultTreeVo> ftList = faultService.listAllListTreeStyleBySimType(simType);
        TaskVo t = new TaskVo();
        t.setTaskId(null);
        t.setSimType(simType);
        t.setTaskType(Task.Type.TEACHER_ADD);
        t.setSelectedData(ftList);
        return t;
    }

    /**
     * 新增任务附带选择故障
     *
     * @param task 任务
     * @return 结果
     */
    @Transactional
    public long insertTaskWithFault(Task task) {
        Long taskId = task.getTaskId();
        if (selectTaskByTaskId(taskId) != null) {
            // 已经存在
        }
        task.setCreateTime(DateUtils.getNowDate());
        task.setUpdateTime(DateUtils.getNowDate());
        return taskMapper.insertTask(task);
    }
}
