package cn.iocoder.yudao.module.pms.service.iotdevicebom;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicebom.vo.IotDeviceBomListReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicebom.vo.IotDeviceBomPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicebom.vo.IotDeviceBomSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmainworkorderbom.vo.IotMainWorkOrderBomPageReqVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.IotDeviceDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdevicebom.IotDeviceBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmaintenancebom.IotMaintenanceBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
import cn.iocoder.yudao.module.pms.dal.mysql.IotDeviceMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotdevicebom.IotDeviceBomMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotmaintenancebom.IotMaintenanceBomMapper;
import cn.iocoder.yudao.module.pms.dal.mysql.iotmainworkorderbom.IotMainWorkOrderBomMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import java.util.*;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_DEVICE_BOM_NOT_EXISTS;
import static cn.iocoder.yudao.module.pms.enums.ErrorCodeConstant.IOT_MAIN_PLAN_ORDER_EXISTS;


/**
 * PMS 设备BOM 关系 Service 实现类
 *
 * @author ruiqi
 */
@Service
@Validated
public class IotDeviceBomServiceImpl implements IotDeviceBomService {

    @Resource
    private IotDeviceBomMapper iotDeviceBomMapper;
    @Resource
    private IotDeviceMapper iotDeviceMapper;
    @Resource
    private IotMaintenanceBomMapper iotMaintenanceBomMapper;
    @Resource
    private IotMainWorkOrderBomMapper iotMainWorkOrderBomMapper;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long createIotDeviceBom(IotDeviceBomSaveReqVO createReqVO) {
        // 插入
        IotDeviceBomDO iotDeviceBom = BeanUtils.toBean(createReqVO, IotDeviceBomDO.class);
        // 设置当前节点为 叶子
        iotDeviceBom.setLeafFlag(1);
        // 设置父节点为 非叶子节点
        if (!createReqVO.getParentId().equals(0L)) {
            IotDeviceBomDO parentBomNode = iotDeviceBomMapper.selectParentNode(createReqVO);
            parentBomNode.setLeafFlag(2);
            iotDeviceBomMapper.updateById(parentBomNode);
        }
        iotDeviceBomMapper.insert(iotDeviceBom);
        // 设置 BOM所属设备的 bom_sync_status = 1
        IotDeviceDO device = iotDeviceMapper.selectById(createReqVO.getDeviceId());
        if (device.getBomSyncStatus() == 0) {
            device.setBomSyncStatus(1);
            iotDeviceMapper.updateById(device);
        }
        // 返回
        return iotDeviceBom.getId();
    }

    @Override
    public void updateIotDeviceBom(IotDeviceBomSaveReqVO updateReqVO) {
        // 校验存在
        IotDeviceBomDO deviceBom = validateIotDeviceBomExists(updateReqVO.getId());
        // 校验 如果当前保养项是否已经存在保养计划 保养工单 并且修改后的保养项 没有设置 保养 选项
        // 提醒 先处理保养计划 或 保养工单 中的保养项
        ValidateResult validateResult = validateExistPlanOrder(deviceBom);
        Map<String, List<IotMaintenanceBomDO>> planBomsPair = validateResult.getPlanBomPair();
        Map<String, List<IotMainWorkOrderBomDO>> orderBomsPair = validateResult.getWorkOrderBomPair();
        if ((CollUtil.isNotEmpty(planBomsPair)
                || CollUtil.isNotEmpty(orderBomsPair)) && !updateReqVO.getType().contains(2)) {
            throw exception(IOT_MAIN_PLAN_ORDER_EXISTS);
        }

        // 更新 保养项
        IotDeviceBomDO updateObj = BeanUtils.toBean(updateReqVO, IotDeviceBomDO.class);
        iotDeviceBomMapper.updateById(updateObj);

        // 如果修改了保养项名称 暂时覆盖 正在运行中的 保养计划 保养工单 明细中对应的 保养项名称
        if (CollUtil.isNotEmpty(planBomsPair)) {
            List<IotMaintenanceBomDO> planBoms = planBomsPair.get("planBoms");
            if (CollUtil.isNotEmpty(planBoms)) {
                // 查询 bomNodeIds 集合中每个bom节点的所有上级节点
                // 查询所有 设备boms节点的所有上级节点名称 拼接出 全路径 的bom节点
                List<Long> bomNodeIds = new ArrayList<>();
                bomNodeIds.add(updateReqVO.getId());
                Map<Long, String> bomFullPaths = buildBomFullPaths(bomNodeIds);
                planBoms.forEach(bom -> {
                    if (bomFullPaths.containsKey(updateReqVO.getId())) {
                        if (StrUtil.isNotBlank(bomFullPaths.get(updateReqVO.getId())) && updateReqVO.getId().equals(bom.getBomNodeId())) {
                            bom.setName(bomFullPaths.get(updateReqVO.getId()));
                        }
                    }
                });
                iotMaintenanceBomMapper.updateBatch(planBoms);
            }
        }
        if (CollUtil.isNotEmpty(orderBomsPair)) {
            List<IotMainWorkOrderBomDO> orderBoms = orderBomsPair.get("orderBoms");
            if (CollUtil.isNotEmpty(orderBoms)) {
                // 查询 bomNodeIds 集合中每个bom节点的所有上级节点
                // 查询所有 设备boms节点的所有上级节点名称 拼接出 全路径 的bom节点
                List<Long> bomNodeIds = new ArrayList<>();
                bomNodeIds.add(updateReqVO.getId());
                Map<Long, String> bomFullPaths = buildBomFullPaths(bomNodeIds);
                orderBoms.forEach(bom -> {
                    if (bomFullPaths.containsKey(updateReqVO.getId())) {
                        if (StrUtil.isNotBlank(bomFullPaths.get(updateReqVO.getId())) && updateReqVO.getId().equals(bom.getBomNodeId())) {
                            bom.setName(bomFullPaths.get(updateReqVO.getId()));
                        }
                    }
                });
                iotMainWorkOrderBomMapper.updateBatch(orderBoms);
            }
        }
        // 设置设备BOM关联的设备的 bom_sync_status = 1
        iotDeviceMapper.updateBomSyncStatus(updateObj.getDeviceId());
    }

    @Override
    public void deleteIotDeviceBom(Long id) {
        // 校验存在
        IotDeviceBomDO deviceBom = validateIotDeviceBomExists(id);
        // 校验当前设备BOM保养项是否已经关联了保养计划 保养工单
        ValidateResult validateResult = validateExistPlanOrder(deviceBom);
        if (CollUtil.isNotEmpty(validateResult.getPlanBomPair())
                || CollUtil.isNotEmpty(validateResult.getWorkOrderBomPair())) {
            throw exception(IOT_MAIN_PLAN_ORDER_EXISTS);
        }
        // 删除
        iotDeviceBomMapper.deleteById(id);
        iotDeviceMapper.updateBomSyncStatus(deviceBom.getDeviceId());

    }

    /**
     * 校验当前保养项是否已经存在关联的保养计划 保养工单
     * @param deviceBom
     * @return
     */
    private ValidateResult validateExistPlanOrder(IotDeviceBomDO deviceBom){
        Map<String, List<IotMaintenanceBomDO>> planBomPair = new HashMap<>();
        Map<String, List<IotMainWorkOrderBomDO>> workOrderBomPair = new HashMap<>();
        // 校验当前设备BOM保养项是否已经关联了保养计划 保养工单
        IotMaintenanceBomPageReqVO bomReqVO = new IotMaintenanceBomPageReqVO();
        bomReqVO.setDeviceId(deviceBom.getDeviceId());
        bomReqVO.setBomNodeId(deviceBom.getId());
        List<IotMaintenanceBomDO> planBoms = iotMaintenanceBomMapper.selectList(bomReqVO);
        if (CollUtil.isNotEmpty(planBoms)) {
            planBomPair.put("planBoms", planBoms);
        }
        // 查询当前设备bom保养项集合关联的 运行中(未保养完成) 的工单
        IotMainWorkOrderBomPageReqVO orderBomReqVO = new IotMainWorkOrderBomPageReqVO();
        orderBomReqVO.setDeviceId(deviceBom.getDeviceId());
        orderBomReqVO.setBomNodeId(deviceBom.getId());
        orderBomReqVO.setStatus(0);
        List<IotMainWorkOrderBomDO> orderBoms = iotMainWorkOrderBomMapper.selectList(orderBomReqVO);
        if (CollUtil.isNotEmpty(orderBoms)) {
            workOrderBomPair.put("orderBoms", orderBoms);
        }
        return new ValidateResult(planBomPair, workOrderBomPair);
    }

    private class ValidateResult {
        private Map<String, List<IotMaintenanceBomDO>> planBomPair;
        private Map<String, List<IotMainWorkOrderBomDO>> workOrderBomPair;

        // 构造方法
        public ValidateResult(Map<String, List<IotMaintenanceBomDO>> planBomPair,
                              Map<String, List<IotMainWorkOrderBomDO>> workOrderBomPair) {
            this.planBomPair = planBomPair;
            this.workOrderBomPair = workOrderBomPair;
        }

        // getter
        public Map<String, List<IotMaintenanceBomDO>> getPlanBomPair() {
            return planBomPair;
        }

        public Map<String, List<IotMainWorkOrderBomDO>> getWorkOrderBomPair() {
            return workOrderBomPair;
        }
    }

    private IotDeviceBomDO validateIotDeviceBomExists(Long id) {
        IotDeviceBomDO deviceBom = iotDeviceBomMapper.selectById(id);
        if (ObjUtil.isEmpty(deviceBom)) {
            throw exception(IOT_DEVICE_BOM_NOT_EXISTS);
        }
        return deviceBom;
    }

    @Override
    public IotDeviceBomDO getIotDeviceBom(Long id) {
        return iotDeviceBomMapper.selectById(id);
    }

    @Override
    public PageResult<IotDeviceBomDO> getIotDeviceBomPage(IotDeviceBomPageReqVO pageReqVO) {
        return iotDeviceBomMapper.selectPage(pageReqVO);
    }

    @Override
    public List<IotDeviceBomDO> getDeviceBomList(IotDeviceBomListReqVO iotDeviceBomListReqVO) {
        List<IotDeviceBomDO> list = iotDeviceBomMapper.selectList(iotDeviceBomListReqVO);
        list.sort(Comparator.comparing(IotDeviceBomDO::getSort));
        return list;
    }

    @Override
    public Map<Long, String> buildBomFullPaths(List<Long> bomNodeIds) {
        // 1. 参数检查
        if (CollUtil.isEmpty(bomNodeIds)) {
            return Collections.emptyMap();
        }

        // 2. 批量查询所有相关节点（包括祖先）
        Set<Long> allNodeIds = new HashSet<>();
        Queue<Long> queue = new LinkedList<>(bomNodeIds);
        allNodeIds.addAll(bomNodeIds);

        // 递归收集父节点ID
        while (!queue.isEmpty()) {
            Long currentId = queue.poll();
            IotDeviceBomDO node = iotDeviceBomMapper.selectById(currentId);
            if (node == null) continue;

            Long parentId = node.getParentId();
            // 有效父节点且未遍历过
            if (parentId != null && parentId > 0 && !allNodeIds.contains(parentId)) {
                allNodeIds.add(parentId);
                queue.offer(parentId);
            }
        }

        // 3. 批量查询节点数据
        Map<Long, IotDeviceBomDO> nodeMap = iotDeviceBomMapper.selectNodeMapByIds(allNodeIds);

        // 4. 构建路径
        Map<Long, String> result = new HashMap<>();
        for (Long nodeId : bomNodeIds) {
            LinkedList<String> pathSegments = new LinkedList<>();
            Long currentId = nodeId;

            // 向上回溯直到根节点
            while (currentId != null && currentId > 0) {
                IotDeviceBomDO node = nodeMap.get(currentId);
                if (node == null) break;

                pathSegments.addFirst(node.getName()); // 头部插入保证顺序
                currentId = node.getParentId();
            }
            result.put(nodeId, String.join("->", pathSegments));
        }
        return result;
    }

}