package com.zksy.base.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zksy.base.domain.EquipmentBase;
import com.zksy.base.domain.EquipmentType;
import com.zksy.base.mapper.EquipmentBaseMapper;
import com.zksy.base.mapper.EquipmentTypeMapper;
import com.zksy.base.service.EquipmentBaseService;
import com.zksy.base.service.EquipmentTypeService;
import com.zksy.common.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

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

//TODO 这里代码待检查
@Slf4j
@Service
public class EquipmentTypeServiceImpl extends ServiceImpl<EquipmentTypeMapper, EquipmentType>
        implements EquipmentTypeService {

    @Autowired
    private EquipmentBaseMapper equipmentBaseMapper;

    @Autowired
    private EquipmentBaseService equipmentBaseService;

    @Override
    public Page<EquipmentType> findByPage(long pageNum, long pageSize, String typeId,String typeName,String parentTypeId) {
        Page<EquipmentType> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<EquipmentType> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(EquipmentType::getId,typeId)
                    .eq(EquipmentType::getTypeName,typeName)
                    .eq(EquipmentType::getParentTypeId,parentTypeId);
        return this.page(page,queryWrapper);
    }

    /**
     * 新增设备类别
     * @param entity
     * @return
     */
    @Override
    public boolean saveWithCheck(EquipmentType entity) {
        //校验父类别是否存在
        String parentId = entity.getParentTypeId();
        // 0表示无父类，无需校验
        if (!"0".equals(parentId)) {
            EquipmentType parent = this.getById(parentId);
            if (parent == null) {
                throw new ServiceException("父类别不存在：" + parentId);
            }
        }

        //校验同一父类别下，类别名称是否重复
        LambdaQueryWrapper<EquipmentType> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EquipmentType::getParentTypeId, parentId)
                .eq(EquipmentType::getTypeName, entity.getTypeName());
        if (this.count(wrapper) > 0) {
            throw new ServiceException("同一父类别下已存在同名类别：" + entity.getTypeName());
        }
        //新增
        return this.save(entity);
    }

    @Override
    @Transactional
    public boolean saveBatchWithCheck(List<EquipmentType> entityList) {

        Set<String> parentIds = new HashSet<>(); // 所有父类别ID
        Map<String, Set<String>> sameParentNames = new HashMap<>(); // 同一父类下的名称集合

        for (EquipmentType entity : entityList) {
            String parentId = entity.getParentTypeId() == null ? "0" : entity.getParentTypeId();
            parentIds.add(parentId);

            // 检查列表内同一父类下是否有重复名称
            sameParentNames.computeIfAbsent(parentId, k -> new HashSet<>())
                    .add(entity.getTypeName());
        }

        //批量校验父类别是否存在
        List<String> existParentIds = this.listByIds(parentIds).stream()
                .map(EquipmentType::getId)
                .collect(Collectors.toList());
        // 过滤出不存在的父类别ID
        Set<String> invalidParentIds = parentIds.stream()
                .filter(id -> !"0".equals(id) && !existParentIds.contains(id))
                .collect(Collectors.toSet());
        if (!invalidParentIds.isEmpty()) {
            throw new ServiceException("存在无效父类别ID：" + invalidParentIds);
        }

        //校验数据库中是否存在同名类别
        for (Map.Entry<String, Set<String>> entry : sameParentNames.entrySet()) {
            String parentId = entry.getKey();
            Set<String> names = entry.getValue();

            LambdaQueryWrapper<EquipmentType> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(EquipmentType::getParentTypeId, parentId)
                    .in(EquipmentType::getTypeName, names);

            List<String> existNames = this.list(wrapper).stream()
                    .map(EquipmentType::getTypeName)
                    .collect(Collectors.toList());
            if (!existNames.isEmpty()) {
                throw new ServiceException("父类别[" + parentId + "]下已存在同名类别：" + existNames);
            }
        }

        //批量保存
        return this.saveBatch(entityList);
    }

    /**
     * 设备类别修改
     * @param entity
     * @return
     */
    @Override
    @Transactional
    public boolean updateWithCheck(EquipmentType entity) {
        //校验当前类别是否存在
        String typeId = entity.getId();
        EquipmentType oldType = this.getById(typeId);
        if (oldType == null) {
            throw new ServiceException("设备类别不存在：" + typeId);
        }

        //处理父类别变更
        String newParentId = entity.getParentTypeId() == null ? "0" : entity.getParentTypeId();
        String oldParentId = oldType.getParentTypeId() == null ? "0" : oldType.getParentTypeId();

        if (!newParentId.equals(oldParentId)) {
            //新父类别必须存在
            if (!"0".equals(newParentId)) {
                EquipmentType newParent = this.getById(newParentId);
                if (newParent == null) {
                    throw new ServiceException("新父类别不存在：" + newParentId);
                }
                if (isChildOrSelf(newParentId, typeId)) {
                    throw new ServiceException("不能将自身或子类别设为父类别：" + newParentId);
                }
            }
        }

        //处理类别名称修改
        String newName = entity.getTypeName();
        if (newName != null && !newName.equals(oldType.getTypeName())) {
            // 同一父类别下不能有同名
            LambdaQueryWrapper<EquipmentType> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(EquipmentType::getParentTypeId, newParentId)
                    .eq(EquipmentType::getTypeName, newName)
                    .ne(EquipmentType::getId, typeId); // 排除自身

            if (this.count(wrapper) > 0) {
                throw new ServiceException("父类别[" + newParentId + "]下已存在同名类别：" + newName);
            }
        }

        //更新
        return this.updateById(entity);
    }

    /**
     * 设备类别删除
     * @param typeId
     * @return
     */
    @Transactional
    public boolean removeWithCheck1(String typeId) {
        // 校验类别是否存在
        EquipmentType type = this.getById(typeId);
        if (type == null) {
            throw new ServiceException("设备类别不存在：" + typeId);
        }

        //校验是否有子设备关联
        LambdaQueryWrapper<EquipmentBase> eqWrapper = new LambdaQueryWrapper<>();
        eqWrapper.eq(EquipmentBase::getEquipmentTypeId, typeId);
        //TODO 待完善
        long relatedEqCount = equipmentBaseMapper.selectCount(eqWrapper);
        if (relatedEqCount > 0) {
            throw new ServiceException("该类别下存在" + relatedEqCount + "台设备，无法删除");
        }

        //校验是否有子类别依赖
        LambdaQueryWrapper<EquipmentType> childWrapper = new LambdaQueryWrapper<>();
        childWrapper.eq(EquipmentType::getParentTypeId, typeId);
        long childTypeCount = this.count(childWrapper);
        if (childTypeCount > 0) {
            throw new ServiceException("该类别下存在" + childTypeCount + "个子类别，无法删除");
        }

        // 4. 执行删除
//        boolean deleted = this.removeById(typeId);
//        if (!deleted) {
//            throw new ServiceException("设备类别删除失败：" + typeId);
//        }
        return this.removeById(typeId);
    }

    /**
     * 设备类别批量删除
     * @param typeIds
     * @return
     */

    @Transactional
    //TODO 这部分逻辑待优化，考虑删还是不删除，的概率是要删的
    public boolean removeBatchWithCheck1(List<String> typeIds) {
        // 1. 基础校验：ID列表不能为空
        if (CollectionUtils.isEmpty(typeIds)) {
            throw new ServiceException("批量删除失败：类别ID列表不能为空");
        }

        // 2. 校验类别是否存在（过滤无效ID）
        List<EquipmentType> existTypes = this.listByIds(typeIds);
        if (existTypes.isEmpty()) {
            throw new ServiceException("批量删除失败：所有类别ID均不存在");
        }
        List<String> existIds = existTypes.stream()
                .map(EquipmentType::getId)
                .collect(Collectors.toList());
        // 记录无效ID（仅警告，不阻断）
        List<String> invalidIds = typeIds.stream()
                .filter(id -> !existIds.contains(id))
                .collect(Collectors.toList());
        if (!invalidIds.isEmpty()) {
            log.warn("批量删除中存在无效类别ID：{}", invalidIds);
        }

        // 3. 校验是否有关联设备（批量检查）
        LambdaQueryWrapper<EquipmentBase> eqWrapper = new LambdaQueryWrapper<>();
        eqWrapper.in(EquipmentBase::getEquipmentTypeId, existIds);
        //TODO 待完善，不确定方法用对没
        List<String> relatedTypeIds = equipmentBaseMapper.selectList(eqWrapper).stream()
                .map(EquipmentBase::getEquipmentTypeId)
                .distinct() // 去重，获取有设备关联的类别ID
                .collect(Collectors.toList());
        if (!relatedTypeIds.isEmpty()) {
            throw new ServiceException("以下类别存在关联设备，无法删除：" + relatedTypeIds);
        }

        // 4. 校验是否有子类别依赖（批量检查）
        LambdaQueryWrapper<EquipmentType> childWrapper = new LambdaQueryWrapper<>();
        childWrapper.in(EquipmentType::getParentTypeId, existIds);
        List<String> hasChildTypeIds = this.list(childWrapper).stream()
                .map(EquipmentType::getParentTypeId)
                .distinct() // 去重，获取有子类别依赖的类别ID
                .collect(Collectors.toList());
        if (!hasChildTypeIds.isEmpty()) {
            throw new ServiceException("以下类别存在子类别，无法删除：" + hasChildTypeIds);
        }

        // 5. 执行批量删除
//        boolean deleted = this.removeByIds(existIds);
//        if (!deleted) {
//            throw new ServiceException("设备类别批量删除失败");
//        }
//        log.info("成功批量删除{}个设备类别", existIds.size());
        return this.removeByIds(existIds);
    }

    /**
     * 设备类别删除（强制删除，先删关联数据）
     */
    @Override
    @Transactional
    public boolean removeWithCheck(String typeId) {
        // 校验类别是否存在
        EquipmentType type = this.getById(typeId);
        if (type == null) {
            throw new ServiceException("设备类别不存在：" + typeId);
        }

        // 先删除关联的设备
        LambdaQueryWrapper<EquipmentBase> eqWrapper = new LambdaQueryWrapper<>();
        eqWrapper.eq(EquipmentBase::getEquipmentTypeId, typeId);
        //TODO 待完善，不确定方法用对没
        List<String> relatedEqIds = equipmentBaseMapper.selectList(eqWrapper).stream()
                .map(EquipmentBase::getEquipmentId)
                .collect(Collectors.toList());
        if (!relatedEqIds.isEmpty()) {
            equipmentBaseService.removeBatchWithCheck(relatedEqIds);
            log.info("已级联删除类别[{}]关联的{}台设备", typeId, relatedEqIds.size());
        }

        // 先删除子类别
        LambdaQueryWrapper<EquipmentType> childWrapper = new LambdaQueryWrapper<>();
        childWrapper.eq(EquipmentType::getParentTypeId, typeId);
        List<String> childTypeIds = this.list(childWrapper).stream()
                .map(EquipmentType::getId)
                .collect(Collectors.toList());
        if (!childTypeIds.isEmpty()) {
            this.removeBatchWithCheck(childTypeIds); // 调用批量删除方法处理子类别
            log.info("已删除类别[{}]的{}个子类别", typeId, childTypeIds.size());
        }
        //删除
        return this.removeById(typeId);
    }

    /**
     * 设备类别批量删除（强制删除，先删关联数据）
     */
    @Override
    @Transactional
    public boolean removeBatchWithCheck(List<String> typeIds) {
        if (CollectionUtils.isEmpty(typeIds)) {
            throw new ServiceException("批量删除失败：类别ID列表不能为空");
        }

        //校验类别是否存在
        List<EquipmentType> existTypes = this.listByIds(typeIds);
        if (existTypes.isEmpty()) {
            throw new ServiceException("批量删除失败：所有类别ID均不存在");
        }
        List<String> existIds = existTypes.stream()
                .map(EquipmentType::getId)
                .collect(Collectors.toList());
        List<String> invalidIds = typeIds.stream()
                .filter(id -> !existIds.contains(id))
                .collect(Collectors.toList());
        if (!invalidIds.isEmpty()) {
            log.warn("批量删除中存在无效类别ID：{}", invalidIds);
        }

        //先批量删除所有关联的设备
        LambdaQueryWrapper<EquipmentBase> eqWrapper = new LambdaQueryWrapper<>();
        eqWrapper.in(EquipmentBase::getEquipmentTypeId, existIds);
        //TODO 待完善，不确定方法用对没
        List<String> relatedEqIds = equipmentBaseMapper.selectList(eqWrapper).stream()
                .map(EquipmentBase::getEquipmentId)
                .collect(Collectors.toList());
        if (!relatedEqIds.isEmpty()) {
            equipmentBaseService.removeBatchWithCheck(relatedEqIds);
            log.info("已批量级联删除{}台关联设备", relatedEqIds.size());
        }

        //先批量删除所有子类别
        List<String> allChildTypeIds = new ArrayList<>();
        collectAllChildTypes(existIds, allChildTypeIds); // 递归收集所有子类别ID
        if (!allChildTypeIds.isEmpty()) {
            this.removeBatchWithCheck(allChildTypeIds); // 批量删除所有子类别
            log.info("已批量删除{}个子类别", allChildTypeIds.size());
        }

        return this.removeByIds(existIds);
    }

    /**
     * 递归收集所有层级的子类别ID
     */
    private void collectAllChildTypes(List<String> parentTypeIds, List<String> allChildTypeIds) {
        LambdaQueryWrapper<EquipmentType> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(EquipmentType::getParentTypeId, parentTypeIds);
        List<String> childIds = this.list(wrapper).stream()
                .map(EquipmentType::getId)
                .collect(Collectors.toList());
        if (!childIds.isEmpty()) {
            allChildTypeIds.addAll(childIds);
            collectAllChildTypes(childIds, allChildTypeIds); // 递归收集下一级子类别
        }
    }

    //检查targetId是否是currentId的子类别或自身
    private boolean isChildOrSelf(String targetId, String currentId) {
        if (targetId.equals(currentId)) {
            //自身不能作为父类别
            return true;
        }
        // 查询targetId的所有子类别
        LambdaQueryWrapper<EquipmentType> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EquipmentType::getParentTypeId, targetId);
        List<EquipmentType> children = this.list(wrapper);
        for (EquipmentType child : children) {
            if (child.getId().equals(currentId) || isChildOrSelf(child.getId(), currentId)) {
                return true;
            }
        }
        return false;
    }
}
