package cn.iocoder.yudao.module.pms.job.mainworkorder;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.quartz.core.handler.JobHandler;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.pms.constant.PmsConstants;
import cn.iocoder.yudao.module.pms.controller.admin.iotdeviceperson.vo.IotDevicePersonPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotdevicerunlog.vo.IotDeviceRunLogRespVO;
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.controller.admin.maintenance.vo.IotMaintenancePlanPageReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.vo.IotDeviceRespVO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotdeviceperson.IotDevicePersonDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmaintenancebom.IotMaintenanceBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorder.IotMainWorkOrderDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
import cn.iocoder.yudao.module.pms.enums.common.FailureAuditStatusEnum;
import cn.iocoder.yudao.module.pms.message.PmsMessage;
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
import cn.iocoder.yudao.module.pms.service.iotdeviceperson.IotDevicePersonService;
import cn.iocoder.yudao.module.pms.service.iotdevicerunlog.IotDeviceRunLogService;
import cn.iocoder.yudao.module.pms.service.iotmaintenancebom.IotMaintenanceBomService;
import cn.iocoder.yudao.module.pms.service.iotmainworkorder.IotMainWorkOrderService;
import cn.iocoder.yudao.module.pms.service.iotmainworkorderbom.IotMainWorkOrderBomService;
import cn.iocoder.yudao.module.pms.service.maintenance.IotMaintenancePlanService;
import cn.iocoder.yudao.module.system.api.user.AdminUserApi;
import cn.iocoder.yudao.module.system.api.user.dto.AdminUserRespDTO;
import cn.iocoder.yudao.module.system.controller.admin.dept.vo.dept.DeptListReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.dept.DeptDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.RoleDO;
import cn.iocoder.yudao.module.system.dal.dataobject.permission.UserRoleDO;
import cn.iocoder.yudao.module.system.dal.mysql.permission.UserRoleMapper;
import cn.iocoder.yudao.module.system.service.dept.DeptService;
import cn.iocoder.yudao.module.system.service.permission.RoleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicLong;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;
import static cn.iocoder.yudao.module.pms.framework.config.MultiThreadConfiguration.PMS_THREAD_POOL_TASK_EXECUTOR;

@Component
@Slf4j
public class CreateMainWorkOrderJob implements JobHandler {
    @Resource
    private IotDevicePersonService iotDevicePersonService;
    @Resource
    private IotMaintenanceBomService iotMaintenanceBomService;
    @Autowired
    private IotDeviceRunLogService iotDeviceRunLogService;

    @Resource
    private IotMaintenancePlanService iotMaintenancePlanService;
    @Resource
    private IotMainWorkOrderService iotMainWorkOrderService;
    @Resource
    private IotMainWorkOrderBomService iotMainWorkOrderBomService;
    @Resource
    private IotDeviceService iotDeviceService;
    @Resource
    private AdminUserApi adminUserApi;
    @Resource(name = PMS_THREAD_POOL_TASK_EXECUTOR)
    private ThreadPoolTaskExecutor pmsThreadPoolTaskExecutor;
    @Resource
    private PmsMessage pmsMessage;
    @Resource
    private DeptService deptService;
    @Resource
    private RoleService roleService;
    @Resource
    private UserRoleMapper userRoleMapper;

    @Override
    @TenantJob
    public String execute(String param) throws Exception {
        // 查询所有 保养计划明细
        IotMaintenanceBomPageReqVO reqVO = new IotMaintenanceBomPageReqVO();
        List<IotMaintenanceBomDO> originMainBomList = iotMaintenanceBomService.getIotMainPlanBomList(reqVO);
        // 查询所有保养计划 保养工单会复制保养计划的部分信息
        IotMaintenancePlanPageReqVO planReqVO = new IotMaintenancePlanPageReqVO();
        // 只查询开启状态的保养计划
        planReqVO.setStatus(CommonStatusEnum.ENABLE.getStatus());
        List<IotMaintenancePlanDO> plans = iotMaintenancePlanService.maintenancePlans(planReqVO);
        if (CollUtil.isEmpty(plans)) {
            return "没有待保养项";
        }
        if (CollUtil.isEmpty(originMainBomList)) {
            return "没有待保养项";
        }
        // 过滤掉停用的保养计划
        List<IotMaintenanceBomDO> mainBomList = new ArrayList<>();
        Set<Long> enabledPlanIds = new HashSet<>();
        plans.forEach(plan -> {
            enabledPlanIds.add(plan.getId());
        });
        originMainBomList.forEach(bom -> {
            if (enabledPlanIds.contains(bom.getPlanId())) {
                mainBomList.add(bom);
            }
        });

        List<Long> deviceIds = new ArrayList<>();
        Set<Long> deviceCategoryIds = new HashSet<>();
        Map<Long, Long> deviceCategoryPair = new HashMap<>();
        // 运行记录模板中 多种 累计时长 公里数 属性名称集合
        Set<String> boundedMultiAttrNames = new HashSet<>();
        mainBomList.forEach(bom -> {
            // 查询保养计划明细中所有设备id
            deviceIds.add(bom.getDeviceId());
            // 查询保养计划明细已经绑定的 多种 累计时长 公里数 属性名称
            if (StrUtil.isNotBlank(bom.getCode())) {
                boundedMultiAttrNames.add(bom.getCode());
            }
            if (StrUtil.isNotBlank(bom.getType())) {
                boundedMultiAttrNames.add(bom.getType());
            }
        });
        if (CollUtil.isEmpty(deviceIds)) {
            return "没有设备信息";
        }
        Map<Long, IotDeviceRespVO> deviceMap = new HashMap<>();
        Map<Long, DeptDO> depts = new HashMap<>();
        if (CollUtil.isNotEmpty(mainBomList)) {
            // 组装bom关联的设备信息
            deviceMap = iotDeviceService.getDeviceMap(convertListByFlatMap(mainBomList,
                    bom -> Stream.of(bom.getDeviceId())));
            if (CollUtil.isNotEmpty(deviceMap)) {
                Set<Long> deptIds = new HashSet<>();
                deviceMap.forEach((k,v) -> {
                    deviceCategoryIds.add(v.getAssetClass());
                    deviceCategoryPair.put(k, v.getAssetClass());
                    deptIds.add(v.getDeptId());
                });
                // 根据部门id集合查询对应的部门名称
                if (CollUtil.isNotEmpty(deptIds)) {
                    depts = deptService.getDeptMap(deptIds);
                }
            }
        }
        // 查询所有设备的责任人
        IotDevicePersonPageReqVO devicePersonReqVO = new IotDevicePersonPageReqVO();
        devicePersonReqVO.setDeviceIds(deviceIds);
        List<IotDevicePersonDO> devicePersons = iotDevicePersonService.getPersonsByDeviceIds(devicePersonReqVO);
        Map<Long, List<Long>> devicePersonPair = new HashMap<>();
        Map<Long, AdminUserRespDTO> userPair = new HashMap<>();
        if (CollUtil.isNotEmpty(devicePersons)) {
            devicePersonPair = devicePersons.stream()
                    .filter(person -> person.getDeviceId() != null) // 过滤deviceId为null的记录
                    .collect(Collectors.groupingBy(
                            IotDevicePersonDO::getDeviceId, // 按deviceId分组
                            Collectors.mapping(
                                    IotDevicePersonDO::getPersonId, // 提取personId
                                    Collectors.toList() // 收集为列表
                            )
                    ));
            Set<Long> personIds = new HashSet<>();
            // 查询所有设备责任人id对应的责任人姓名(昵称)
            devicePersons.forEach(dp -> {
                personIds.add(dp.getPersonId());
            });
            userPair = adminUserApi.getUserMap(personIds);
        }
        // 查询 保养计划保养明细中已经绑定的 多种累计时长 公里数 属性集合
        List<IotDeviceRunLogRespVO> multipleAccumulatedData = new ArrayList<>();
        if (CollUtil.isNotEmpty(deviceIds) && CollUtil.isNotEmpty(boundedMultiAttrNames)) {
            multipleAccumulatedData = iotDeviceRunLogService.multipleAccumulatedData(deviceIds, boundedMultiAttrNames, null);
        }
        // key(设备id-累计时长属性名称)    value时长属性累计时长数值
        Map<String, BigDecimal> tempTotalRunDataPair = new HashMap<>();
        if (CollUtil.isNotEmpty(multipleAccumulatedData)) {
            multipleAccumulatedData.forEach(data -> {
                String uniqueKey = StrUtil.join("-", data.getDeviceId(), data.getPointName());
                tempTotalRunDataPair.put(uniqueKey, data.getTotalRunTime());
            });
        }

        // 查询保养计划明细中所有设备的累计运行里程、累计运行时间
        Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap = iotDeviceRunLogService.getDeviceRunLogMapAlone(convertListByFlatMap(mainBomList,
                bom -> Stream.of(bom.getDeviceId())), new ArrayList<>(deviceCategoryIds), deviceCategoryPair, null);
        List<IotMaintenanceBomDO> tobeMaintenanceBomList = new ArrayList<>();
        // 触发保养规则的设备id 集合
        List<Long> tobeMainDeviceIds = new ArrayList<>();
        // 触发保养规则的设备bom节点id 集合
        List<Long> tobeMainBomIds = new ArrayList<>();
        // 遍历保养计划明细 根据保养项规则 筛选出当前满足保养项规则的 明细记录
        mainBomList.forEach(bom -> {
            boolean runningTimeArrive = false;
            boolean runningKiloArrive = false;
            boolean naturalDateArrive = false;
            // 只有维护了累计运行时间、累计运行里程 运行记录的设备才能触发 里程周期 时间周期 保养规则
            BigDecimal totalRunTime = BigDecimal.ZERO;
            BigDecimal totalMileage = BigDecimal.ZERO;
            if (deviceRunLogMap.containsKey(bom.getDeviceId())) {
                // 正常的累计时长 公里数
                totalRunTime = deviceRunLogMap.get(bom.getDeviceId()).getTotalRunTime();
                totalMileage = deviceRunLogMap.get(bom.getDeviceId()).getTotalMileage();
            } else {
                // 保养项绑定的 累计时长 类型的属性值
                String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getCode());
                if (tempTotalRunDataPair.containsKey(uniqueKey)) {
                    totalRunTime = tempTotalRunDataPair.get(uniqueKey);
                }
                // 保养项绑定的 累计公里数类型的属性值
                String uniqueKeyType = StrUtil.join("-", bom.getDeviceId(), bom.getType());
                if (tempTotalRunDataPair.containsKey(uniqueKeyType)) {
                    totalMileage = tempTotalRunDataPair.get(uniqueKeyType);
                }
            }
            if (ObjUtil.isNotEmpty(bom.getRunningTimeRule()) && 0 == bom.getRunningTimeRule()) {
                // 累计运行时间规则   累计运行时间 >= (上次保养运行时间+运行时间周期-提前量)
                BigDecimal lastRunningTime = bom.getLastRunningTime();      // 上次保养运行时间
                BigDecimal runningTimePeriod = bom.getNextRunningTime();    // 运行时间周期
                BigDecimal timePeriodLead = bom.getTimePeriodLead();        // 运行时间周期提前量
                if (((runningTimePeriod.subtract(totalRunTime.subtract(lastRunningTime))).subtract(timePeriodLead)).compareTo(BigDecimal.ZERO) <= 0) {
                    runningTimeArrive = true;
                }
            }
            if (ObjUtil.isNotEmpty(bom.getMileageRule()) && 0 == bom.getMileageRule()) {
                // 累计运行里程规则 累计运行里程 >= (上次保养运行里程+运行里程周期-提前量)
                BigDecimal lastRunningKilo = bom.getLastRunningKilometers();      // 上次保养运行里程
                BigDecimal runningKiloPeriod = bom.getNextRunningKilometers();    // 运行里程周期
                BigDecimal kiloCycleLead = bom.getKiloCycleLead();                // 运行里程周期提前量
                if (((runningKiloPeriod.subtract(totalMileage.subtract(lastRunningKilo))).subtract(kiloCycleLead)).compareTo(BigDecimal.ZERO) <= 0) {
                    runningTimeArrive = true;
                }
            }
            // 没有维护 累计运行时间、累计运行里程 运行记录的设备 可以触发 自然日周期 保养规则
            if (ObjUtil.isNotEmpty(bom.getNaturalDateRule()) && 0 == bom.getNaturalDateRule()) {
                // 自然日期规则  当前日期 >= (上次保养自然日期+自然日周期-提前量)
                LocalDateTime lastNaturalDate = bom.getLastNaturalDate();      // 上次保养自然日期
                BigDecimal naturalDatePeriod = bom.getNextNaturalDate();       // 自然日周期
                BigDecimal natualDateLead = bom.getNaturalDatePeriodLead();    // 自然日周期提前量
                if (ObjUtil.isNotEmpty(lastNaturalDate) && ObjUtil.isNotEmpty(naturalDatePeriod) && ObjUtil.isNotEmpty(natualDateLead)) {
                    // 计算有效天数 = 自然日周期 - 提前量
                    long days = naturalDatePeriod.subtract(natualDateLead).longValue(); // 转为长整型天数
                    // 计算目标日期：上次保养日期 + 有效天数（注意：LocalDateTime加天数会自动处理日期进位）
                    LocalDateTime targetDate = lastNaturalDate.plusDays(days);
                    // 获取当前日期时间（可根据需求调整为指定时区，如：ZoneId.systemDefault()）
                    LocalDateTime now = LocalDateTime.now();
                    // 判断当前时间是否大于等于目标日期
                    naturalDateArrive = now.isAfter(targetDate) || now.isEqual(targetDate);
                }
            }
            if (runningTimeArrive || runningKiloArrive || naturalDateArrive) {
                // 3个保养规则中有任何一个规则达到条件即触发 保养
                tobeMaintenanceBomList.add(bom);
                tobeMainDeviceIds.add(bom.getDeviceId());
                tobeMainBomIds.add(bom.getBomNodeId());
            }
        });
        // key保养计划id    value保养计划
        Map<Long, IotMaintenancePlanDO> maintenancePair = new HashMap<>();
        plans.forEach(plan -> {
            maintenancePair.put(plan.getId(), plan);
        });
        if (CollUtil.isNotEmpty(tobeMaintenanceBomList)) {
            // 如果有可以触发的保养项 查询保养工单明细中是否存在相同保养项 未填报完成的保养工单 如果有则不生成新的保养工单
            IotMainWorkOrderBomPageReqVO bomReqVO = new IotMainWorkOrderBomPageReqVO();
            bomReqVO.setDeviceIds(tobeMainDeviceIds);
            bomReqVO.setBomNodeIds(tobeMainBomIds);
            bomReqVO.setStatus(0);
            List<IotMainWorkOrderBomDO> workOrderBomS = iotMainWorkOrderBomService.getIotMainWorkOrderBomList(bomReqVO);
            Set<Long> existDeviceIds = new HashSet<>();
            Set<Long> existBomNodeIds = new HashSet<>();
            if (CollUtil.isNotEmpty(workOrderBomS)) {
                workOrderBomS.forEach(bom -> {
                    existDeviceIds.add(bom.getDeviceId());
                    existBomNodeIds.add(bom.getBomNodeId());
                });
            }
            // 暂时使用以保养计划为维度，生成保养工单
            // 查询最新的保养工单id
            AtomicLong theMaxId = new AtomicLong(iotMainWorkOrderService.theMaxWorkOrderId());
            List<IotMainWorkOrderDO> workOrders = new ArrayList<>();
            List<IotMainWorkOrderBomDO> workOrderBOMs = new ArrayList<>();
            // 组装 工单明细 集合
            // 根据保养计划明细中的 保养项的保养规则 生成保养工单明细
            tobeMaintenanceBomList.forEach(bom -> {
                if (!(existDeviceIds.contains(bom.getDeviceId()) && existBomNodeIds.contains(bom.getBomNodeId()))) {
                    // 当前保养项存在 未填报完成的保养工单 不能生成新工单
                    IotMainWorkOrderBomDO workOrderBom = new IotMainWorkOrderBomDO();
                    workOrderBom.setWorkOrderId(bom.getPlanId());   // 以保养计划planId当作保养工单明细分组的标识
                    workOrderBom.setDeviceCategoryId(bom.getDeviceCategoryId());
                    workOrderBom.setDeviceId(bom.getDeviceId());
                    workOrderBom.setMileageRule(bom.getMileageRule());
                    workOrderBom.setRunningTimeRule(bom.getRunningTimeRule());
                    workOrderBom.setNaturalDateRule(bom.getNaturalDateRule());
                    workOrderBom.setLastRunningTime(bom.getLastRunningTime());
                    workOrderBom.setNextRunningTime(bom.getNextRunningTime());
                    workOrderBom.setTimePeriodLead(bom.getTimePeriodLead());
                    workOrderBom.setLastRunningKilometers(bom.getLastRunningKilometers());
                    workOrderBom.setNextRunningKilometers(bom.getNextRunningKilometers());
                    workOrderBom.setKiloCycleLead(bom.getKiloCycleLead());
                    workOrderBom.setLastNaturalDate(bom.getLastNaturalDate());
                    workOrderBom.setNextNaturalDate(bom.getNextNaturalDate());
                    workOrderBom.setNaturalDatePeriodLead(bom.getNaturalDatePeriodLead());
                    workOrderBom.setBomNodeId(bom.getBomNodeId());
                    workOrderBom.setName(bom.getName());
                    workOrderBom.setCode(bom.getCode());
                    workOrderBom.setType(bom.getType());
                    workOrderBOMs.add(workOrderBom);
                }
            });
            // 以保养计划id对待保养工单分组 分组后便于生成 保养工单主表记录
            // key保养计划id value待保养工单明细集合
            // Map<Long, List<IotMainWorkOrderBomDO>> workOrderBomPair = new HashMap<>();
            // 以设备为维度 统计每种设备对应的 保养项集合 key保养计划id+设备id value设备对应的保养项集合
            Map<String, List<IotMainWorkOrderBomDO>> deviceBomPair = new HashMap<>();
            // 最终使用的保养工单明细 设置了保养工单主表id
            List<IotMainWorkOrderBomDO> finalWorkOrderBomS = new ArrayList<>();
            if (CollUtil.isNotEmpty(workOrderBOMs)) {
                // 组装设备及对应的 保养项集合 map
                workOrderBOMs.forEach(bom -> {
                    String uniqueKey = bom.getWorkOrderId() + "-" + bom.getDeviceId();
                    if (deviceBomPair.containsKey(uniqueKey)) {
                        List<IotMainWorkOrderBomDO> tempOrderBomS = deviceBomPair.get(uniqueKey);
                        tempOrderBomS.add(bom);
                        deviceBomPair.put(uniqueKey, tempOrderBomS);
                    } else {
                        List<IotMainWorkOrderBomDO> tempOrderBomS = new ArrayList<>();
                        tempOrderBomS.add(bom);
                        deviceBomPair.put(uniqueKey, tempOrderBomS);
                    }
                });

                // 按照 保养计划id+设备id 分组 每个"保养计划id+设备id" 生成一个工单
                Map<Long, List<Long>> finalDevicePersonPair = devicePersonPair;
                // 获取当前时间的 yyyy-MM-dd 格式
                String currentDate = LocalDateTime.now().format(DateTimeFormatter.ofPattern(DateUtils.FORMAT_YEAR_MONTH_DAY));
                Map<Long, AdminUserRespDTO> finalUserPair = userPair;
                Map<Long, IotDeviceRespVO> finalDeviceMap = deviceMap;
                Map<Long, DeptDO> finalDepts = depts;
                deviceBomPair.forEach((k, v) -> {
                    String[] planIdDeviceIdStrS = k.split("-");
                    // 查询当前设备关联的责任人 如果有多个责任人 需要建立多个对应的工单 但是多个工单 要建立关联关系
                    if (finalDevicePersonPair.containsKey(Long.valueOf(planIdDeviceIdStrS[1]))) {
                        List<Long> personIds = finalDevicePersonPair.get(Long.valueOf(planIdDeviceIdStrS[1]));
                        if (CollUtil.isNotEmpty(personIds)) {
                            // 多个责任人的相同工单 使用 order_group_id 建立关联
                            String orderGroupId = StrUtil.uuid();
                            personIds.forEach(personId -> {
                                // k保养计划id   v已经触发的保养工单明细
                                IotMaintenancePlanDO plan = maintenancePair.get(Long.valueOf(planIdDeviceIdStrS[0]));
                                IotMainWorkOrderDO workOrder = new IotMainWorkOrderDO();
                                long newId = theMaxId.incrementAndGet(); // 原子操作：+1并返回新值
                                workOrder.setId(newId);
                                // 设备多个责任人关联工单标识
                                workOrder.setOrderGroupId(orderGroupId);
                                // 查询设备对应的部门
                                workOrder.setDeptId(plan.getDeptId());
                                workOrder.setName(plan.getName() + " 工单");
                                if (finalDeviceMap.containsKey(Long.valueOf(planIdDeviceIdStrS[1]))) {
                                    Long deptId = finalDeviceMap.get(Long.valueOf(planIdDeviceIdStrS[1])).getDeptId();
                                    // 设备编码
                                    String deviceCode = finalDeviceMap.get(Long.valueOf(planIdDeviceIdStrS[1])).getDeviceCode();
                                    workOrder.setDeptId(deptId);
                                    // 查询 deptId 对应的部门名称
                                    String deptName = StrUtil.EMPTY;
                                    String deptCHName = StrUtil.EMPTY;
                                    String deptENName = StrUtil.EMPTY;
                                    if (finalDepts.containsKey(deptId)) {
                                        DeptDO dept = finalDepts.get(deptId);
                                        deptName = dept.getName();
                                        // 提取部门英文名称
                                        String[] deptNameStr = deptName.split("~~");
                                        deptCHName = (deptNameStr.length > 0) ? deptNameStr[0] : StrUtil.EMPTY;
                                        deptENName = StrUtil.EMPTY;
                                        if (deptNameStr.length > 0) {
                                            for (String s : deptNameStr) {
                                                if (s.contains("en")) {
                                                    deptENName = s;
                                                }
                                            }
                                        }
                                    }
                                    // 查询 personId 对应的责任人名称(昵称)
                                    String responsibleName = StrUtil.EMPTY;
                                    if (finalUserPair.containsKey(personId)) {
                                        AdminUserRespDTO userDTO = finalUserPair.get(personId);
                                        responsibleName = userDTO.getNickname();
                                    }
                                    // 设备名称 提取英文名称
                                    String deviceName = finalDeviceMap.get(Long.valueOf(planIdDeviceIdStrS[1])).getDeviceName();
                                    String[] deviceNameStr = deviceName.split("~~");
                                    String deviceCHName = (deviceNameStr.length > 0) ? deviceNameStr[0] : StrUtil.EMPTY;
                                    String deviceENName = StrUtil.EMPTY;
                                    if (deviceNameStr.length > 0) {
                                        for (String s : deviceNameStr) {
                                            if (s.contains("en")) {
                                                deviceENName = s;
                                            }
                                        }
                                    }
                                    String workOrderCHName = StrUtil.EMPTY;
                                    workOrderCHName = deptCHName + "/" + responsibleName + "/" + deviceCode + "/"
                                            + deviceCHName + "/" + currentDate + "-保养工单";
                                    String workOrderENName = StrUtil.EMPTY;
                                    if (StrUtil.isNotBlank(deviceENName) && StrUtil.isNotBlank(deptENName)) {
                                        workOrderENName = deptENName + "/" + responsibleName + "/" + deviceCode + "/"
                                                + deviceENName + "/" + currentDate + "-Maintenance Work Order";
                                    }
                                    workOrder.setName(workOrderCHName + "~~en**" + workOrderENName);
                                } else {
                                    // 如果设备列表没有包含需要保养的设备id 不生成保养工单 提示
                                    System.out.println("不存在数据 - 待保养的设备id：" + planIdDeviceIdStrS[1]);
                                    // 跳过当前循环 继续下次循环
                                    return;
                                }
                                workOrder.setPlanId(plan.getId());
                                workOrder.setOrderNumber(iotMainWorkOrderService.createWorkOrderNumber());
                                workOrder.setType(1);   // 计划生成
                                workOrder.setResult(1); // 待执行
                                workOrder.setResponsiblePerson(String.valueOf(personId));
                                workOrder.setAuditStatus(FailureAuditStatusEnum.DRAFT.getStatus());
                                workOrder.setCreator(String.valueOf(personId));
                                workOrders.add(workOrder);
                                // 2. 处理关联的BOM明细
                                final long workOrderId = workOrder.getId(); // 获取当前工单ID
                                v.forEach(bom -> {
                                    IotMainWorkOrderBomDO tempBom = new IotMainWorkOrderBomDO();
                                    BeanUtils.copyProperties(bom,tempBom);
                                    tempBom.setWorkOrderId(workOrderId);
                                    finalWorkOrderBomS.add(tempBom);
                                });
                            });
                        }
                    }
                });
            }
            // 批量新增 保养工单记录
            if (CollUtil.isNotEmpty(workOrders)) {
                // 插入数据时深拷贝集合 后续发送消息提醒时需要用到 工单 id
                List<IotMainWorkOrderDO> copiedWorkOrders = new ArrayList<>();
                copiedWorkOrders.addAll(workOrders);
                // 深度拷贝工单对象
                List<IotMainWorkOrderDO> deepCopiedOrders = workOrders.stream()
                        .map(order -> {
                            IotMainWorkOrderDO copy = new IotMainWorkOrderDO();
                            // 手动复制所有属性（根据实际字段补充）
                            copy.setOrderGroupId(order.getOrderGroupId());
                            copy.setDeptId(order.getDeptId());
                            copy.setName(order.getName());
                            copy.setPlanId(order.getPlanId());
                            copy.setOrderNumber(order.getOrderNumber());
                            copy.setType(order.getType());
                            copy.setResult(order.getResult());
                            copy.setResponsiblePerson(order.getResponsiblePerson());
                            copy.setAuditStatus(order.getAuditStatus());
                            copy.setCreator(order.getCreator());
                            // 注意：不要复制ID，由服务层生成
                            copy.setId(order.getId());
                            return copy;
                        })
                        .collect(Collectors.toList());

                iotMainWorkOrderService.batchAddOrders(deepCopiedOrders);
            }
            // 批量新增 保养工单明细
            if (CollUtil.isNotEmpty(finalWorkOrderBomS)) {
                iotMainWorkOrderBomService.batchAddOrderBOMs(finalWorkOrderBomS);
            }
            // 向工单责任人发送 站内信及 钉钉消息
            if (CollUtil.isNotEmpty(workOrders)) {
                // 查询 字段 email 值 = 新疆项目管理RY 的部门
                DeptListReqVO deptReqVO = new DeptListReqVO();
                deptReqVO.setEmail("新疆项目管理RY");
                List<DeptDO> departments = deptService.getDeptList(deptReqVO);
                Set<Long> parentDeptIds = new HashSet<>();
                if (CollUtil.isNotEmpty(departments)) {
                    departments.forEach(dept -> {
                        parentDeptIds.add(dept.getId());
                    });
                }
                // 查询用户手机号的用户列表
                Set<Long> targetUserIds = new HashSet<>();
                if (CollUtil.isNotEmpty(parentDeptIds)) {
                    // 查询指定角色对应的用户
                    RoleDO role = roleService.getRoleByCode("新疆项目管理RY");
                    if (ObjUtil.isNotEmpty(role)) {
                        Set<Long> roleIds = new HashSet<>();
                        roleIds.add(role.getId());
                        List<UserRoleDO> userRoles = userRoleMapper.selectListByRoleIds(roleIds);
                        if (CollUtil.isNotEmpty(userRoles)) {
                            // 提取有审批角色的所有用户ID（去重+空值过滤）
                            Set<Long> roleUserIds = userRoles.stream()
                                    .map(UserRoleDO::getUserId)
                                    .filter(Objects::nonNull) // 过滤空userId
                                    .collect(Collectors.toSet());
                            targetUserIds.addAll(roleUserIds);
                        }
                    }
                }

                // 先查询所有工单责任人的手机号
                Set<Long> personIds = new HashSet<>(convertList(workOrders, order -> Long.valueOf(order.getResponsiblePerson())));
                if (CollUtil.isNotEmpty(targetUserIds)) {
                    personIds.addAll(targetUserIds);
                }
                Map<Long, AdminUserRespDTO> users = adminUserApi.getUserMap(personIds);
                // 建立保养工单与 用户手机号的 对应关系
                Map<Long, String> orderMobilePair = new HashMap<>();
                Set<Long> orderDeptIds = new HashSet<>();
                workOrders.forEach(order -> {
                    if (users.containsKey(Long.valueOf(order.getResponsiblePerson()))) {
                        AdminUserRespDTO user = users.get(Long.valueOf(order.getResponsiblePerson()));
                        orderMobilePair.put(order.getId(), user.getMobile());
                    }
                    // 收集所有工单的部门 查询上级部门是否是 瑞鹰-新疆项目部
                    orderDeptIds.add(order.getDeptId());
                });

                // 查询工单部门信息
                Set<Long> ryXjDeptIds = new HashSet<>();
                if (CollUtil.isNotEmpty(orderDeptIds)) {
                    List<DeptDO> deptInfos = deptService.getDeptList(orderDeptIds);
                    if (CollUtil.isNotEmpty(deptInfos)) {
                        deptInfos.forEach(dept -> {
                            if (parentDeptIds.contains(dept.getParentId())) {
                                ryXjDeptIds.add(dept.getId());
                            }
                        });
                    }
                }
                System.out.println("目标部门id集合：" + ryXjDeptIds.size());
                // 异步多线程发送 站内信 钉钉 消息
                // 如果是 瑞鹰 新疆项目部的保养工单，需要提醒到 ‘新疆项目管理RY’ 角色
                workOrders.forEach(order -> {
                    CountDownLatch latch = new CountDownLatch(workOrders.size());
                    pmsThreadPoolTaskExecutor.execute(() -> {
                        try {
                            if (orderMobilePair.containsKey(order.getId())) {
                                String mobile = orderMobilePair.get(order.getId());
                                pmsMessage.sendMessage(order.getId(), order.getName(), PmsConstants.GENERATE_MAINTENANCE,
                                        Long.valueOf(order.getResponsiblePerson()), mobile);
                                // 如果是瑞鹰的 新疆项目部保养工单 同时提醒到 指定拥有指定角色 新疆项目管理RY 的人
                                System.out.println("工单部门id：" + order.getDeptId());
                                System.out.println("目标用户id集合：" + targetUserIds.size());
                                if (ryXjDeptIds.contains(order.getDeptId())) {
                                    if (CollUtil.isNotEmpty(targetUserIds)) {
                                        List<Long> userIdList = new ArrayList<>(targetUserIds);
                                        Long targetUserId = userIdList.get(0);
                                        if (users.containsKey(targetUserId)) {
                                            AdminUserRespDTO targetUser = users.get(targetUserId);
                                            String targetUserMobile = targetUser.getMobile();
                                            pmsMessage.sendMessage(order.getId(), order.getName(), PmsConstants.GENERATE_MAINTENANCE,
                                                    targetUserId, targetUserMobile);
                                        }
                                    }
                                }
                            }
                        } finally {
                            latch.countDown();
                        }
                    });
                });
            }
        }
        return "创建成功";
    }
}
