package com.ruoyi.sim.service.impl;

import java.util.*;
import java.util.stream.Collectors;

import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.sim.domain.TaskFault;
import com.ruoyi.sim.domain.vo.FaultShowVo;
import com.ruoyi.sim.domain.vo.FaultTreeVo;
import org.apache.commons.lang3.RandomUtils;
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.FaultMapper;
import com.ruoyi.sim.domain.Fault;

/**
 * 故障Service业务层处理
 *
 * @author tom
 * @date 2024-12-15
 */
@Service
public class FaultService {
    @Autowired
    private FaultMapper faultMapper;

    /**
     * 查询故障
     *
     * @param faultId 故障主键
     * @return 故障
     */
    public Fault selectFaultByFaultId(String faultId) {
        return faultMapper.selectFaultByFaultId(faultId);
    }

    /**
     * 查询故障列表
     *
     * @param fault 故障
     * @return 故障
     */
    public List<Fault> selectFaultList(Fault fault) {
        return faultMapper.selectFaultList(fault);
    }

    /**
     * 新增故障
     *
     * @param fault 故障
     * @return 结果
     */
    public int insertFault(Fault fault) {
        fault.setCreateTime(DateUtils.getNowDate());
        return faultMapper.insertFault(fault);
    }

    /**
     * 修改故障
     *
     * @param fault 故障
     * @return 结果
     */
    public int updateFault(Fault fault) {
        fault.setUpdateTime(DateUtils.getNowDate());
        return faultMapper.updateFault(fault);
    }

    /**
     * 批量删除故障
     *
     * @param faultIds 需要删除的故障主键
     * @return 结果
     */
    public int deleteFaultByFaultIds(String[] faultIds) {
        return faultMapper.deleteFaultByFaultIds(faultIds);
    }

    /**
     * 删除故障信息
     *
     * @param faultId 故障主键
     * @return 结果
     */
    public int deleteFaultByFaultId(String faultId) {
        return faultMapper.deleteFaultByFaultId(faultId);
    }

    // -------------------------------- tom add  --------------------------------
    private static final Logger l = LoggerFactory.getLogger(FaultService.class);
    @Autowired
    private SimService simService;

    public boolean isEnable(final String faultId) {
        Fault q = new Fault();
        q.setFaultId(faultId);
        Fault f = selectFaultByFaultId(faultId);
        if (f == null) {
            return false;
        }
        return (Fault.State.ENABLE.equals(f.getFaultState()));
    }

    public boolean isDisable(String faultId) {
        return !isEnable(faultId);
    }

    public boolean isExist(final String simType, final String faultId) {
        Fault f = selectFaultByFaultId(faultId);
        if (f == null) {
            return false;
        }
        return f.getSimType().equals(simType);
    }

    public boolean isExist(final String simType, final String[] faultIds) {
        if (faultIds == null || faultIds.length == 0) {
            return false;
        }
        for (String faultId : faultIds) {
            if (!isExist(simType, faultId)) {
                return false;
            }
        }
        return true;
    }

    public List<Fault> listAllEnable(final String simType) {
        Fault q = new Fault();
        q.setSimType(simType);
        q.setFaultState(Fault.State.ENABLE);
        return selectFaultList(q);
    }

    public List<Fault> listType3EnableBySimType(final String simType) {
        Fault q = new Fault();
        q.setSimType(simType);
        q.setFaultType(Fault.Type.REAL_GZBW);
        q.setFaultState(Fault.State.ENABLE);
        return selectFaultList(q);
    }

    public List<Fault> listType1And3EnableBySimType(final String simType) {
        List<Fault> list = new ArrayList<>();
        listAllEnable(simType)
                .stream()
                .filter(Objects::nonNull)
                .filter(f ->
                        (Fault.State.ENABLE.equals(f.getFaultState()))
                )
                .filter(f ->
                        (Fault.Type.GZXX.equals(f.getFaultType()) || Fault.Type.REAL_GZBW.equals(f.getFaultType()))
                )
                .forEach(list::add);
        return list;
    }

    /**
     * 通过模拟器类型，[查询故障]列表。tree形式。
     *
     * @param simType 模拟器型号
     */
    public AjaxResult listAllTreeStyleBySimType(final String simType) {
        // check
        if (StringUtils.isEmpty(simType)) {
            return AjaxResult.error("simType empty!");
        }
        if (!simService.checkSimTypeOk(simType)) {
            return AjaxResult.error("simType value error!");
        }
        // do.
        return AjaxResult.success(listAllListTreeStyleBySimType(simType));
    }

    /**
     * list某模拟器型号，所有的 包括真实的，虚假的，[故障部位]基础数据。
     *
     * @param simType
     * @return
     */
    public AjaxResult listType3and30(final String simType) {
        // check
        if (StringUtils.isEmpty(simType)) {
            return AjaxResult.error("simType empty!");
        }
        if (!simService.checkSimTypeOk(simType)) {
            return AjaxResult.error("simType value error!");
        }
        // do query.
        List<Fault> list1 = new ArrayList<>();
        Fault q3 = new Fault();
        q3.setSimType(simType);
        q3.setFaultState(Fault.State.ENABLE);
        q3.setFaultType(Fault.Type.REAL_GZBW);
        list1.addAll(selectFaultList(q3));
        Fault q30 = new Fault();
        q30.setSimType(simType);
        q30.setSimType(simType);
        q30.setFaultState(Fault.State.ENABLE);
        q30.setFaultType(Fault.Type.FAKE_GZBW);
        list1.addAll(selectFaultList(q30));
        Collections.sort(list1);
        List<FaultShowVo> list2 = new ArrayList<>();
        for (Fault f : list1) {
            FaultShowVo vo = new FaultShowVo();
            BeanUtils.copyProperties(f, vo);
            list2.add(vo);
        }
        return AjaxResult.success(list2);
    }

    /**
     * list某模拟器型号，所有的 包括真实的[故障部位]基础数据。
     *
     * @param simType
     * @return
     */
    public AjaxResult listType3Ar(final String simType) {
        // check
        if (StringUtils.isEmpty(simType)) {
            return AjaxResult.error("simType empty!");
        }
        if (!simService.checkSimTypeOk(simType)) {
            return AjaxResult.error("simType value error!");
        }
        List<Fault> list1 = listType3(simType);
        List<FaultShowVo> list2 = new ArrayList<>();
        for (Fault f : list1) {
            FaultShowVo vo = new FaultShowVo();
            BeanUtils.copyProperties(f, vo);
            list2.add(vo);
        }
        return AjaxResult.success(list2);
    }

    public List<Fault> listType3(final String simType) {
        // do query.
        List<Fault> list1 = new ArrayList<>();
        Fault q3 = new Fault();
        q3.setSimType(simType);
        q3.setFaultState(Fault.State.ENABLE);
        q3.setFaultType(Fault.Type.REAL_GZBW);
        list1.addAll(selectFaultList(q3));
        // faultId 升序排序
        Collections.sort(list1);
        return list1;
    }

    /**
     * list某模拟器型号，所有[故障现象]基础数据。
     *
     * @param simType
     * @return
     */
    public AjaxResult listEnableByType(final String simType, final String faultType) {
        // check
        if (StringUtils.isEmpty(simType)) {
            return AjaxResult.error("simType empty!");
        }
        if (!simService.checkSimTypeOk(simType)) {
            return AjaxResult.error("simType value error!");
        }
        // do query.
        List<Fault> list1 = new ArrayList<>();
        Fault q = new Fault();
        q.setSimType(simType);
        q.setFaultState(Fault.State.ENABLE);
        q.setFaultType(faultType);
        list1.addAll(selectFaultList(q));
        List<FaultShowVo> list2 = new ArrayList<>();
        for (Fault f : list1) {
            FaultShowVo vo = new FaultShowVo();
            BeanUtils.copyProperties(f, vo);
            list2.add(vo);
        }
        return AjaxResult.success(list2);
    }

    /**
     * todo: 修改成数据库查询。
     *
     * @param simType
     * @param faultType
     * @return
     */
    public List<Fault> listEnableByTypeZZZZ(final String simType, final String faultType) {
        List<Fault> list1 = new ArrayList<>();
        Fault q = new Fault();
        q.setSimType(simType);
        q.setFaultState(Fault.State.ENABLE);
        q.setFaultType(faultType);
        list1.addAll(selectFaultList(q));
        return list1;
    }


    /**
     * 根据模拟器型号，查询故障列表tree。
     *
     * @param simType
     */
    public List<FaultTreeVo> listAllListTreeStyleBySimType(final String simType) {
        List<Fault> list = listType1And3EnableBySimType(simType);
        // 排序。按照faultId升序排序
        Collections.sort(list);
        List<FaultTreeVo> tempListNode = new ArrayList<>();
        for (Fault s : list) {
            FaultTreeVo t = new FaultTreeVo();
            BeanUtils.copyProperties(s, t);
            tempListNode.add(t);
        }
        // l.info(Objects.requireNonNull(tempListNode).toString());
        List<FaultTreeVo> tree = toTree(tempListNode, Fault.ROOT_FAULT_ID);
        // l.info(Objects.requireNonNull(tree).toString());
        return tree;
    }

    /**
     * 通过Type3 List 获取到不重复的Type1 List。·
     *
     * @param list
     * @return
     */
    public List<Fault> listType1ByType3(List<Fault> list) {
        if (list == null || list.isEmpty()) {
            return Collections.emptyList();
        }
        String[] faultIds = new String[list.size()];
        for (int i = 0; i < list.size(); i++) {
            faultIds[i] = list.get(i).getFaultId();
        }
        return setType1ByType3(faultIds).stream().toList();
    }

    public int countType1ByType3(List<Fault> list) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        return listType1ByType3(list).size();
    }

    public Set<Fault> setType1ByType3(String[] faultIdsType3) {
        if (faultIdsType3 == null || faultIdsType3.length == 0) {
            return Collections.emptySet();
        }
        Set<Fault> set = new HashSet<>();
        for (String id : faultIdsType3) {
            Fault t3 = selectFaultByFaultId(id);
            Fault t1 = selectFaultByFaultId(t3.getParentFaultId());
            set.add(t1);
        }
        return set;
    }

    public boolean isType(String faultId, String type) {
        if (StringUtils.isBlank(type)) {
            return false;
        }
        Fault f = selectFaultByFaultId(faultId);
        if (f == null) {
            return false;
        }
        return type.equals(f.getFaultType());
    }

    public boolean isType3(String faultId) {
        return isType(faultId, Fault.Type.REAL_GZBW);
    }

    public static int COUNT_3 = 3;

    public List<Fault> randomEnable3(final String simType) {
        return randomEnable(simType, COUNT_3);
    }

    /**
     * 随机出题。
     *
     * @param simType
     * @param selectCount 选中题目数量。
     * @return
     */
    public List<Fault> randomEnable(final String simType, final int selectCount) {
        List<Fault> list1 = listType3EnableBySimType(simType);
        Set<Fault> set = new HashSet<>();
        for (int i = 0; i < selectCount; i++) {
            int index = RandomUtils.nextInt(0, list1.size() - i);
            set.add(list1.get(index));
            list1.remove(index);
        }
        if (set.size() != selectCount) {
            throw new RuntimeException("randomEnable fail!");
        }
        return set.stream().toList();
    }

//    private static List<FaultNode> toTree2(List<FaultNode> list) {
//        List<FaultNode> tree = new ArrayList<>();
//        for (FaultNode fn1 : list) {
//            if (fn1.getParentFaultId().equals(ROOT_FAULT_ID)) {
//                tree.add(fn1);
//            }
//            for (FaultNode fn2 : list) {
//                if (fn2.getParentFaultId().equals(fn1.getParentFaultId())) {
//                    if (fn1.getChildren() == null) {
//                        fn1.setChildren(new ArrayList<>());
//                    }
//                    fn1.getChildren().add(fn2);
//                }
//            }
//        }
//        return tree;
//    }

    public static List<FaultTreeVo> toTree(List<FaultTreeVo> list, String parentFaultId) {
        // todo:sort
        List<FaultTreeVo> tree = list
                .stream()
                .filter(
                        parent ->
                                parent.getParentFaultId().equals(parentFaultId))
                .map(child -> {
                    if (child.getTaskFault() == null) {
                        child.setTaskFault(new TaskFault(0L, 0L, child.getFaultId(), TaskFault.Flag.UNKNOWN));
                    }
                    child.setChildren(toTree(list, child.getFaultId()));
                    return child;
                })
                .collect(Collectors.toList());
        return tree;
    }

    public static List<FaultTreeVo> flatten(List<FaultTreeVo> list) {
        return list
                // todo:stream filter

//                .stream()
//                .filter(x -> {
//                    return StringUtils.isEmpty(x.getParentFaultId());
//                })
//                .collect(Collectors.toList())
                .stream()
                .map(x -> {
                    return flatten(x, list);
                })
                .flatMap(Collection::stream)
                .distinct()
                .collect(Collectors.toList());
    }

    public static List<FaultTreeVo> flatten(FaultTreeVo node, List<FaultTreeVo> list2222) {
        List<FaultTreeVo> results = new ArrayList<>();
        if (node != null) {
            // get rid of children & parent references
            FaultTreeVo target = new FaultTreeVo();
            BeanUtils.copyProperties(node, target);
            results.add(target);
        }

        List<FaultTreeVo> children = node.getChildren();
        for (FaultTreeVo child : children) {
            if (child.getChildren() != null) {
                // Recursive call - Keep flattening until no more children
                List<FaultTreeVo> flatten = flatten(child, list2222);
                results.addAll(flatten);
            }
        }
        // stop or exit condition
        return results;
    }
}
