package cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.common.util.number.NumberUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
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.iotmaintenancebom.vo.IotMaintenanceBomRespVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmaintenancebom.vo.IotMaintenanceBomSaveReqVO;
import cn.iocoder.yudao.module.pms.controller.admin.iotmodeltemplateattrs.vo.IotModelTemplateAttrsPageReqVO;
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.iotmaintenancebom.IotMaintenanceBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmainworkorderbom.IotMainWorkOrderBomDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.iotmodeltemplateattrs.IotModelTemplateAttrsDO;
import cn.iocoder.yudao.module.pms.dal.dataobject.maintenance.IotMaintenancePlanDO;
import cn.iocoder.yudao.module.pms.service.IotDeviceService;
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.iotmodeltemplateattrs.IotModelTemplateAttrsService;
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 io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Stream;

import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.EXPORT;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertListByFlatMap;

@Tag(name = "管理后台 - PMS 保养计划明细BOM")
@RestController
@RequestMapping("/pms/iot-maintenance-bom")
@Validated
public class IotMaintenanceBomController {

    @Resource
    private IotMaintenanceBomService iotMaintenanceBomService;
    @Resource
    private IotDeviceService iotDeviceService;
    @Resource
    private IotDeviceRunLogService iotDeviceRunLogService;
    @Resource
    private IotModelTemplateAttrsService iotModelTemplateAttrsService;
    @Resource
    private IotMainWorkOrderService iotMainWorkOrderService;
    @Resource
    private IotMaintenancePlanService iotMaintenancePlanService;
    @Resource
    private AdminUserApi adminUserApi;

    @PostMapping("/create")
    @Operation(summary = "创建PMS 保养计划明细BOM")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:create')")
    public CommonResult<Long> createIotMaintenanceBom(@Valid @RequestBody IotMaintenanceBomSaveReqVO createReqVO) {
        return success(iotMaintenanceBomService.createIotMaintenanceBom(createReqVO));
    }

    @PutMapping("/update")
    @Operation(summary = "更新PMS 保养计划明细BOM")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:update')")
    public CommonResult<Boolean> updateIotMaintenanceBom(@Valid @RequestBody IotMaintenanceBomSaveReqVO updateReqVO) {
        iotMaintenanceBomService.updateIotMaintenanceBom(updateReqVO);
        return success(true);
    }

    @DeleteMapping("/delete")
    @Operation(summary = "删除PMS 保养计划明细BOM")
    @Parameter(name = "id", description = "编号", required = true)
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:delete')")
    public CommonResult<Boolean> deleteIotMaintenanceBom(@RequestParam("id") Long id) {
        iotMaintenanceBomService.deleteIotMaintenanceBom(id);
        return success(true);
    }

    @GetMapping("/get")
    @Operation(summary = "获得PMS 保养计划明细BOM")
    @Parameter(name = "id", description = "编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:query')")
    public CommonResult<IotMaintenanceBomRespVO> getIotMaintenanceBom(@RequestParam("id") Long id) {
        IotMaintenanceBomDO iotMaintenanceBom = iotMaintenanceBomService.getIotMaintenanceBom(id);
        return success(BeanUtils.toBean(iotMaintenanceBom, IotMaintenanceBomRespVO.class));
    }

    @GetMapping("/page")
    @Operation(summary = "获得PMS 保养计划明细BOM分页")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:query')")
    public CommonResult<PageResult<IotMaintenanceBomRespVO>> getIotMaintenanceBomPage(@Valid IotMaintenanceBomPageReqVO pageReqVO) {
        PageResult<IotMaintenanceBomDO> pageResult = iotMaintenanceBomService.getIotMaintenanceBomPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, IotMaintenanceBomRespVO.class));
    }

    @GetMapping("/getMainPlanBOMs")
    @Operation(summary = "获得PMS 保养计划明细BOM列表")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:query')")
    public CommonResult<List<IotMaintenanceBomRespVO>> getMainPlanBOMs(@Valid IotMaintenanceBomPageReqVO reqVO) {
        List<IotMaintenanceBomDO> workOrderBOMs = iotMaintenanceBomService.getIotMainPlanBomList(reqVO);
        // 组装bom关联的设备名称 编码
        // 组装bom关联的设备 累计运行时间、累计运行公里数
        return success(buildMainPlanBomList(workOrderBOMs));
    }

    private List<IotMaintenanceBomRespVO> buildMainPlanBomList(List<IotMaintenanceBomDO> BOMs) {
        if (CollUtil.isEmpty(BOMs)) {
            return Collections.emptyList();
        }
        // 组装bom关联的设备信息
        Map<Long, IotDeviceRespVO> deviceMap = iotDeviceService.getDeviceMap(convertListByFlatMap(BOMs,
                bom -> Stream.of(bom.getDeviceId())));
        // 查询所有保养明细 已经 绑定了多个累计属性的记录
        Set<String> pointNames = new HashSet<>();
        // 多个累计类型属性名称集合
        Set<String> multiPointNames = new HashSet<>();
        // 保养计划中保养项BOM节点id集合
        Set<Long> bomNodeIds = new HashSet<>();
        BOMs.forEach(bom -> {
            if (StrUtil.isNotBlank(bom.getCode())) {
                pointNames.add(bom.getCode());
            }
            if (StrUtil.isNotBlank(bom.getType())) {
                pointNames.add(bom.getType());
            }
            bomNodeIds.add(bom.getBomNodeId());
        });

        // 设备对应的设备分类 map
        Map<Long, Long> deviceCategoryPair = new HashMap<>();
        Set<Long> deviceCategoryIds = new HashSet<>();
        // 设备id集合 根据设备id查询 运行记录模板中包含多个累计类型属性的 累计时长 累计公里数
        Set<Long> deviceIds = new HashSet<>();
        // 通过设备id集合查询到设备分类id集合
        if (CollUtil.isNotEmpty(deviceMap)) {
            deviceMap.forEach((k,v) -> {
                deviceIds.add(k);
                deviceCategoryIds.add(v.getAssetClass());
                deviceCategoryPair.put(k, v.getAssetClass());
            });
        }

        // 查询所有保养项 历史保养记录 (保养项所有历史工单中最新的保养时间)
        Map<String, LocalDateTime> latestMaintenanceDatePair = new HashMap<>();
        if (CollUtil.isNotEmpty(deviceIds) && CollUtil.isNotEmpty(bomNodeIds)) {
            List<IotMainWorkOrderBomDO> latestWorkOrderBomS = iotMainWorkOrderService.historyWorkOrderBoms(deviceIds, bomNodeIds);
            if (CollUtil.isNotEmpty(latestWorkOrderBomS)) {
                latestWorkOrderBomS.forEach(bom -> {
                    String uniqueKey = StrUtil.join("-", bom.getDeviceId(), bom.getBomNodeId());
                    latestMaintenanceDatePair.put(uniqueKey, bom.getUpdateTime());
                });
            }
        }
        // k设备id   v设备分类包含的模板中与累计运行时长、累计运行公里数相关的属性(正常属性)集合
        Map<Long, List<IotModelTemplateAttrsDO>> deviceAttrsPair = new HashMap<>();
        // k设备id   v设备分类包含的模板中与累计运行时长、累计运行公里数相关的属性(多种累计属性)集合
        Map<Long, List<String>> deviceMultiAttrsPair = new HashMap<>();
        if (CollUtil.isNotEmpty(deviceCategoryIds)) {
            // 查询设备分类id集合对应的运行记录模板中涉及多个 累计运行时长、累计运行公里数 的属性
            IotModelTemplateAttrsPageReqVO multiReqVO = new IotModelTemplateAttrsPageReqVO();
            multiReqVO.setMultipleFlag("Y");
            multiReqVO.setDeviceCategoryIds(new ArrayList<>(deviceCategoryIds));
            multiReqVO.setIsSum(1);  // 累计属性标识
            List<IotModelTemplateAttrsDO> multiAccumulatedAttrs = iotModelTemplateAttrsService.getIotDeviceTemplateAttrs(multiReqVO);
            // k设备分类id   v设备分类包含的模板中 多个 累计运行时长 累计运行公里数相关的属性集合
            Map<Long, List<String>> multiAccumulatedAttrPair = new HashMap<>();
            if (CollUtil.isNotEmpty(multiAccumulatedAttrs)) {
                // 组装不同设备分类下的 多累计类型属性名称集合
                multiAccumulatedAttrs.forEach(attr -> {
                    if (multiAccumulatedAttrPair.containsKey(attr.getDeviceCategoryId())) {
                        List<String> tempAttrs = multiAccumulatedAttrPair.get(attr.getDeviceCategoryId());
                        tempAttrs.add(attr.getName());
                        multiAccumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                    } else {
                        List<String> tempAttrs = new ArrayList<>();
                        tempAttrs.add(attr.getName());
                        multiAccumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                    }
                });
                // 所有 多累计类型属性名称 集合
                multiAccumulatedAttrs.forEach(attr -> {
                    multiPointNames.add(attr.getName());
                });
            }

            // 查询设备分类id集合对应的运行记录模板中涉及 累计运行时长、累计运行公里数 的属性
            IotModelTemplateAttrsPageReqVO reqVO = new IotModelTemplateAttrsPageReqVO();
            List<String> codes = new ArrayList<>(Arrays.asList("sc", "gls"));
            reqVO.setCodes(codes);
            reqVO.setDeviceCategoryIds(new ArrayList<>(deviceCategoryIds));
            reqVO.setIsSum(1);  // 累计属性标识
            // 查询标识的累计类型属性 累计运行时长 累计运行公里数 正常的累计属性
            List<IotModelTemplateAttrsDO> accumulatedAttrs = iotModelTemplateAttrsService.getIotDeviceTemplateAttrs(reqVO);
            // k设备分类id   v设备分类包含的模板中与累计运行时长 累计运行公里数相关的属性集合
            Map<Long, List<IotModelTemplateAttrsDO>> accumulatedAttrPair = new HashMap<>();
            if (CollUtil.isNotEmpty(accumulatedAttrs)) {
                accumulatedAttrs.forEach(attr -> {
                    if (accumulatedAttrPair.containsKey(attr.getDeviceCategoryId())) {
                        List<IotModelTemplateAttrsDO> tempAttrs = accumulatedAttrPair.get(attr.getDeviceCategoryId());
                        tempAttrs.add(attr);
                        accumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                    } else {
                        List<IotModelTemplateAttrsDO> tempAttrs = new ArrayList<>();
                        tempAttrs.add(attr);
                        accumulatedAttrPair.put(attr.getDeviceCategoryId(), tempAttrs);
                    }
                });
            }
            if (CollUtil.isNotEmpty(accumulatedAttrPair)) {
                accumulatedAttrPair.forEach((k,v) -> {
                    // k设备分类id   v设备分类包含的模板中与累计运行时长 累计运行公里数相关的属性集合
                    deviceCategoryPair.forEach((ik, iv) -> {
                        // ik设备id   iv设备分类id
                        if (iv.equals(k)) {
                            deviceAttrsPair.put(ik, v);
                        }
                    });
                });
            }
            // 将多累计时长 公里数属性名称集合的 key 值由设备分类id 修改成 设备id
            if (CollUtil.isNotEmpty(multiAccumulatedAttrPair)) {
                multiAccumulatedAttrPair.forEach((k,v) -> {
                    // k设备分类id   v设备分类包含的模板中与累计运行时长 累计运行公里数相关的属性名称集合
                    deviceCategoryPair.forEach((ik, iv) -> {
                        // ik设备id   iv设备分类id
                        if (iv.equals(k)) {
                            deviceMultiAttrsPair.put(ik, v);
                        }
                    });
                });
            }
        }
        // key设备id  value设备对应的运行记录模板中涉及多个累计时长累计公里数的属性集合
        Map<Long, List<IotDeviceRunLogRespVO>> deviceRunLogPair = new HashMap<>();
        // key(设备id-累计时长属性名称)    value时长属性累计时长数值
        Map<String, BigDecimal> tempTotalRunDataPair = new HashMap<>();
        // 查询 运行记录模板中包含多个累计 时长 公里数 属性的集合
        List<IotDeviceRunLogRespVO> multipleAccumulatedData = new ArrayList<>();
        // key(设备id-累计公里数属性名称)    value公里数属性累计公里数值
        Map<String, BigDecimal> tempTotalMileagePair = new HashMap<>();
        // 查询指定设备 指定 多累计属性名称 的设备运行记录数据集合数据
        if (CollUtil.isNotEmpty(deviceIds) && CollUtil.isNotEmpty(multiPointNames)) {
            // TODO 修改成查询 max_run_log 表
            multipleAccumulatedData = iotDeviceRunLogService.multipleAccumulatedData(deviceIds, multiPointNames, null);
        }
        if (CollUtil.isNotEmpty(multipleAccumulatedData)) {
            multipleAccumulatedData.forEach(data -> {
                String uniqueKey = StrUtil.join("-", data.getDeviceId(), data.getPointName());
                tempTotalRunDataPair.put(uniqueKey, data.getTotalRunTime());
                // 设置每个设备对应的多个累计类型属性值 运行记录填报的值 集合
                if (deviceRunLogPair.containsKey(data.getDeviceId())) {
                    List<IotDeviceRunLogRespVO> tempRunLogs = deviceRunLogPair.get(data.getDeviceId());
                    tempRunLogs.add(data);
                    deviceRunLogPair.put(data.getDeviceId(), tempRunLogs);
                } else {
                    List<IotDeviceRunLogRespVO> tempRunLogs = new ArrayList<>();
                    tempRunLogs.add(data);
                    deviceRunLogPair.put(data.getDeviceId(), tempRunLogs);
                }
            });
        }

        // deviceRunLogPair 集合中如果存在未生成运行记录的 多累计属性 自动补全
        Map<Long, List<IotDeviceRunLogRespVO>> copyDeviceRunLogPair = new HashMap<>(deviceRunLogPair);
        deviceRunLogPair.forEach((deviceId, runLogs) -> {
            List<IotDeviceRunLogRespVO> copyRunLogs = copyDeviceRunLogPair.get(deviceId);
            List<IotDeviceRunLogRespVO> timeRunLogs = deviceRunLogPair.get(deviceId);
            copyDeviceRunLogPair.get(deviceId);
            if (deviceMultiAttrsPair.containsKey(deviceId)) {
                List<String> multiAttrNames = deviceMultiAttrsPair.get(deviceId);
                List<IotDeviceRunLogRespVO> unRunLogs = new ArrayList<>();
                if (CollUtil.isNotEmpty(multiAttrNames) && (multiAttrNames.size() > copyRunLogs.size())) {
                    multiAttrNames.forEach(attr -> {
                        timeRunLogs.forEach(runLog -> {
                            if (!attr.equals(runLog.getPointName())) {
                                // 当前的多累计属性没有产生运行记录数据
                                IotDeviceRunLogRespVO tempRunLog = new IotDeviceRunLogRespVO();
                                tempRunLog.setPointName(attr);
                                tempRunLog.setType(1);
                                tempRunLog.setDeviceId(runLog.getDeviceId());
                                unRunLogs.add(tempRunLog);
                            }
                        });
                    });
                    timeRunLogs.addAll(unRunLogs);
                    copyDeviceRunLogPair.put(deviceId, timeRunLogs);
                }
            }
        });

        // 查询正常的累计运行时长 公里数 时需要 携带 设备分类id 方便快速定位 累计属性值
        // 相同设备如果都包含 totalRuntime totalMileage 则返回1个对象
        Map<Long, IotDeviceRunLogRespVO> deviceRunLogMap = iotDeviceRunLogService.getDeviceRunLogMapAlone(convertListByFlatMap(BOMs,
                bom -> Stream.of(bom.getDeviceId())), new ArrayList<>(deviceCategoryIds), deviceCategoryPair, null);
        // 没有产生运行记录的单累计属性 返回前端 0 deviceAttrsPair单属性属性集合
        if (CollUtil.isNotEmpty(deviceAttrsPair)) {
            deviceAttrsPair.forEach((deviceId, attrs) -> {
                if (!deviceRunLogMap.containsKey(deviceId)) {
                    // 当前设备没有产生运行记录数据
                    attrs.forEach(attr -> {
                        IotDeviceRunLogRespVO runLog = new IotDeviceRunLogRespVO();
                        runLog.setTotalRunTime(BigDecimal.ZERO);
                        runLog.setTotalMileage(BigDecimal.ZERO);
                        runLog.setPointName(attr.getName());
                        deviceRunLogMap.put(deviceId, runLog);
                    });
                }
            });
        }
        // 2. 转换成 VO
        return BeanUtils.toBean(BOMs, IotMaintenanceBomRespVO.class, bomVO -> {
            // 设置设备相关信息
            MapUtils.findAndThen(deviceMap, bomVO.getDeviceId(),
                    device -> bomVO.setDeviceName(device.getDeviceName()));
            MapUtils.findAndThen(deviceMap, bomVO.getDeviceId(),
                    device -> bomVO.setDeviceCode(device.getDeviceCode()));
            // 获取设备ID对应的累积类型的属性集合 正常的累计类型属性
            List<IotModelTemplateAttrsDO> deviceAttrs = deviceAttrsPair.get(bomVO.getDeviceId());
            if (CollUtil.isNotEmpty(deviceAttrs) && deviceAttrs.size() > 2) {
                // 模板属性中有多个 累计运行时长 或 累计运行公里数 属性 需要使用另外的方式赋值(保养计划配置时 绑定运行记录模板属性)
            } else {
                MapUtils.findAndThen(deviceRunLogMap, bomVO.getDeviceId(),
                        device -> bomVO.setTotalMileage(device.getTotalMileage()));
                MapUtils.findAndThen(deviceRunLogMap, bomVO.getDeviceId(),
                        device -> bomVO.setTotalRunTime(device.getTotalRunTime()));
            }
            // 组装 运行记录模板中包含的多个累计类型属性
            if (StrUtil.isNotBlank(bomVO.getCode())) {
                // code 累计运行时长属性名称
                String uniqueKey = StrUtil.join("-", bomVO.getDeviceId(), bomVO.getCode());
                if (tempTotalRunDataPair.containsKey(uniqueKey)) {
                    bomVO.setTempTotalRunTime(tempTotalRunDataPair.get(uniqueKey));
                }
            }
            if (StrUtil.isNotBlank(bomVO.getType())) {
                // type 累计运行公里数属性名称
                String uniqueKey = StrUtil.join("-", bomVO.getDeviceId(), bomVO.getType());
                if (tempTotalRunDataPair.containsKey(uniqueKey)) {
                    bomVO.setTempTotalMileage(tempTotalRunDataPair.get(uniqueKey));
                }
            }
            // 如果多累计时长 公里数属性 没有运行记录填报数据，且运行记录模板中 属性标识符没有配置 累计时长 累计公里数 只返回 属性名称集合
            if (copyDeviceRunLogPair.containsKey(bomVO.getDeviceId())) {
                // 设置每个保养项对应的 多个累计类型属性集合 包含属性的运行记录值
                // 区分开 时间 里程 的累计属性列表 便于前端选择
                List<IotDeviceRunLogRespVO> mileageRunLogs = new ArrayList<>();
                List<IotDeviceRunLogRespVO> timeRunLogs = copyDeviceRunLogPair.get(bomVO.getDeviceId());
                timeRunLogs.forEach(log -> {
                    log.setType(1);
                    IotDeviceRunLogRespVO tempRunLog = new IotDeviceRunLogRespVO();
                    BeanUtils.copyProperties(log, tempRunLog);
                    tempRunLog.setType(2);
                    mileageRunLogs.add(tempRunLog);
                });
                bomVO.setTimeAccumulatedAttrs(timeRunLogs);
                bomVO.setMileageAccumulatedAttrs(mileageRunLogs);
            } else {
                // 如果多累计属性没有运行记录填报值 则直接返回 名称 可以设置 累计运行时长 或 公里数 为 0
                List<IotDeviceRunLogRespVO> mileageRunLogs = new ArrayList<>();
                List<IotDeviceRunLogRespVO> timeRunLogs = new ArrayList<>();
                if (deviceMultiAttrsPair.containsKey(bomVO.getDeviceId()) && !deviceAttrsPair.containsKey(bomVO.getDeviceId())) {
                    List<String> attrNames = deviceMultiAttrsPair.get(bomVO.getDeviceId());
                    attrNames.forEach(attrName -> {
                        IotDeviceRunLogRespVO tempRunLog = new IotDeviceRunLogRespVO();
                        tempRunLog.setDeviceId(bomVO.getDeviceId());
                        tempRunLog.setTotalRunTime(BigDecimal.ZERO);
                        tempRunLog.setPointName(attrName);
                        timeRunLogs.add(tempRunLog);
                        tempRunLog.setTotalRunTime(BigDecimal.ZERO);
                        mileageRunLogs.add(tempRunLog);
                    });
                    bomVO.setTimeAccumulatedAttrs(timeRunLogs);
                    bomVO.setMileageAccumulatedAttrs(mileageRunLogs);
                }
            }
            // 设置保养项的上次保养时间
            String uniqueKey = StrUtil.join("-", bomVO.getDeviceId(), bomVO.getBomNodeId());
            if (latestMaintenanceDatePair.containsKey(uniqueKey)) {
                bomVO.setLastMaintenanceDate(latestMaintenanceDatePair.get(uniqueKey));
            }
        });
    }

    @GetMapping("/deviceAssociateBomPage")
    @Operation(summary = "获得PMS 保养计划明细 设备关联-BOM分页")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:query')")
    public CommonResult<PageResult<IotMaintenanceBomRespVO>> deviceAssociateBomPage(@Valid IotMaintenanceBomPageReqVO pageReqVO) {
        PageResult<IotMaintenanceBomDO> pageResult = iotMaintenanceBomService.deviceAssociateBomPage(pageReqVO);
        return success(BeanUtils.toBean(pageResult, IotMaintenanceBomRespVO.class));
    }

    @GetMapping("/export-excel")
    @Operation(summary = "导出PMS 保养计划明细BOM Excel")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportIotMaintenanceBomExcel(@Valid IotMaintenanceBomPageReqVO pageReqVO,
              HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<IotMaintenanceBomDO> list = iotMaintenanceBomService.getIotMaintenanceBomPage(pageReqVO).getList();
        // 导出 Excel
        ExcelUtils.write(response, "PMS 保养计划明细BOM.xls", "数据", IotMaintenanceBomRespVO.class,
                        BeanUtils.toBean(list, IotMaintenanceBomRespVO.class));
    }

    @GetMapping("/exportPlans")
    @Operation(summary = "导出PMS 保养计划明细列表 主表附加到明细表 Excel")
    @PreAuthorize("@ss.hasPermission('pms:iot-maintenance-bom:export')")
    @ApiAccessLog(operateType = EXPORT)
    public void exportPlans(@Valid IotMaintenanceBomPageReqVO pageReqVO,
                                             HttpServletResponse response) throws IOException {
        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        // 先查询符合条件的保养计划 id 集合
        // 再根据 保养计划id 集合 查询所有保养计划明细
        IotMaintenancePlanPageReqVO planReqVO = new IotMaintenancePlanPageReqVO();
        BeanUtils.copyProperties(pageReqVO, planReqVO);
        if (StrUtil.isNotBlank(pageReqVO.getName())) {
            planReqVO.setName(pageReqVO.getName());
        }
        planReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
        List<IotMaintenancePlanDO> plans = iotMaintenancePlanService.getIotMaintenancePlanPage(planReqVO).getList();
        Map<Long, IotMaintenancePlanDO> planPair = new HashMap<>();
        List<Long> planIds = new ArrayList<>();
        if (CollUtil.isNotEmpty(plans)) {
            plans.forEach(plan -> {
                planIds.add(plan.getId());
                planPair.put(plan.getId(), plan);
            });
        }
        pageReqVO.setPlanIds(planIds);
        List<IotMaintenanceBomDO> list = iotMaintenanceBomService.getIotMainPlanBomList(pageReqVO);
        List<IotMaintenanceBomRespVO> planBoms = buildMainPlanBomList(list);
        // 查询保养计划 负责人
        Map<Long, AdminUserRespDTO> userMap = adminUserApi.getUserMap(convertListByFlatMap(plans,
                plan -> Stream.of(NumberUtils.parseLong(plan.getResponsiblePerson()))));
        if (CollUtil.isNotEmpty(planBoms)) {
            planBoms.forEach(bom -> {
                // 保养计划明细
                if (planPair.containsKey(bom.getPlanId())) {
                    IotMaintenancePlanDO plan = planPair.get(bom.getPlanId());
                    bom.setPlanName(plan.getName());
                    bom.setSerialNumber(plan.getSerialNumber());
                    // 计划负责人
                    if (userMap.containsKey(Long.valueOf(plan.getResponsiblePerson()))) {
                        bom.setResponsiblePersonName(userMap.get(Long.valueOf(plan.getResponsiblePerson())).getNickname());
                    }
                }
                // 设置保养规则
                if (bom.getMileageRule() == 0) {
                    bom.setMileageRuleName("是");
                } else {
                    bom.setMileageRuleName("否");
                }
                // 运行时间规则
                if (bom.getRunningTimeRule() == 0) {
                    bom.setRunningTimeRuleName("是");
                } else {
                    bom.setRunningTimeRuleName("否");
                }
                // 自然日期规则
                if (bom.getNaturalDateRule() == 0) {
                    bom.setNaturalDateRuleName("是");
                } else {
                    bom.setNaturalDateRuleName("否");
                }
            });
        }
        // 导出 Excel
        ExcelUtils.write(response, "保养计划明细.xls", "保养计划明细", IotMaintenanceBomRespVO.class,
                planBoms);
    }

}