/*
 * Copyright [2022] [https://www.xiaonuo.vip]
 *
 * Snowy采用APACHE LICENSE 2.0开源协议，您在使用过程中，需要注意以下几点：
 *
 * 1.请不要删除和修改根目录下的LICENSE文件。
 * 2.请不要删除和修改Snowy源码头部的版权声明。
 * 3.本项目代码可免费商业使用，商业使用请保留源码和相关描述文件的项目出处，作者声明等。
 * 4.分发源码时候，请注明软件出处 https://www.xiaonuo.vip
 * 5.不可二次分发开源参与同类竞品，如有想法可联系团队xiaonuobase@qq.com商议合作。
 * 6.若您的项目无法满足以上几点，需要更多功能代码，获取Snowy商业授权许可，请在官网购买授权，地址为 https://www.xiaonuo.vip
 */
package vip.xiaonuo.coldchain.modular.monitordevice.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollStreamUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.jfcloud.influxdb.flux.AggregationWindow;
import com.github.jfcloud.influxdb.flux.QueryCondition;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import rk.netDevice.sdk.p2.ParamData;
import rk.netDevice.sdk.p2.ParamIdsData;
import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
import vip.xiaonuo.coldchain.core.bean.influxdb.SensorData;
import vip.xiaonuo.coldchain.core.cache.monitordevice.MonitorDeviceCache;
import vip.xiaonuo.coldchain.core.config.JfcloudColdChainConstants;
import vip.xiaonuo.coldchain.core.config.JfcloudRedisCacheService;
import vip.xiaonuo.coldchain.core.renke.RenKeService;
import vip.xiaonuo.coldchain.core.service.JfcloudSensorDataService;
import vip.xiaonuo.coldchain.modular.monitordevice.dto.MonitorDevicePageDto;
import vip.xiaonuo.coldchain.modular.monitordevice.entity.MonitorDevice;
import vip.xiaonuo.coldchain.modular.monitordevice.entity.MonitorDeviceTemplate;
import vip.xiaonuo.coldchain.modular.monitordevice.enums.MonitorDeviceStatusEnum;
import vip.xiaonuo.coldchain.modular.monitordevice.handler.CustomCellWriteHandler;
import vip.xiaonuo.coldchain.modular.monitordevice.mapper.MonitorDeviceMapper;
import vip.xiaonuo.coldchain.modular.monitordevice.param.MonitorDeviceAddParam;
import vip.xiaonuo.coldchain.modular.monitordevice.param.MonitorDeviceEditParam;
import vip.xiaonuo.coldchain.modular.monitordevice.param.MonitorDeviceIdParam;
import vip.xiaonuo.coldchain.modular.monitordevice.param.MonitorDevicePageParam;
import vip.xiaonuo.coldchain.modular.monitordevice.service.MonitorDeviceService;
import vip.xiaonuo.coldchain.modular.monitordevicetype.entity.CountEntity;
import vip.xiaonuo.coldchain.modular.monitordevicetype.entity.MonitorDeviceType;
import vip.xiaonuo.coldchain.modular.monitordevicetype.enums.MonitorDeviceTypeEnum;
import vip.xiaonuo.coldchain.modular.monitordevicetype.service.MonitorDeviceTypeService;
import vip.xiaonuo.coldchain.modular.monitortarget.param.TargetStatus;
import vip.xiaonuo.coldchain.modular.monitortarget.service.MonitorTargetService;
import vip.xiaonuo.coldchain.modular.monitortargetregion.entity.MonitorTargetRegion;
import vip.xiaonuo.coldchain.modular.monitortargetregion.service.MonitorTargetRegionService;
import vip.xiaonuo.common.enums.CommonDeleteFlagEnum;
import vip.xiaonuo.common.enums.CommonSortOrderEnum;
import vip.xiaonuo.common.exception.CommonException;
import vip.xiaonuo.common.page.CommonPageRequest;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 采集器管理Service接口实现类
 *
 * @author 黄渊昊
 * @date 2024/11/13 16:55
 **/
@Service
@RequiredArgsConstructor
@Slf4j
public class MonitorDeviceServiceImpl extends ServiceImpl<MonitorDeviceMapper, MonitorDevice> implements MonitorDeviceService {
    private final RenKeService renKeService;
    private final MonitorDeviceCache monitorDeviceCache;
    private final JfcloudSensorDataService sensorDataService;

    @Resource
    private MonitorDeviceTypeService monitorDeviceTypeService;
    @Resource
    private MonitorTargetRegionService monitorTargetRegionService;
    @Resource
    private MonitorTargetService monitorTargetService;
    @Resource
    JfcloudRedisCacheService jfcloudRedisCacheService;
    private String bucketName;

    @Override
    public Page<?> page(MonitorDevicePageParam monitorDevicePageParam) {
        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
        QueryWrapper<MonitorDevice> queryWrapper = new QueryWrapper<MonitorDevice>().checkSqlInjection();
        if (ObjectUtil.isNotEmpty(monitorDevicePageParam.getDeviceName())) {
            queryWrapper.lambda().like(MonitorDevice::getDeviceName, monitorDevicePageParam.getDeviceName());
        }
        if (ObjectUtil.isNotEmpty(monitorDevicePageParam.getDeviceCode())) {
            queryWrapper.lambda().eq(MonitorDevice::getDeviceCode, monitorDevicePageParam.getDeviceCode());
        }
        if (ObjectUtil.isAllNotEmpty(monitorDevicePageParam.getSortField(), monitorDevicePageParam.getSortOrder())) {
            CommonSortOrderEnum.validate(monitorDevicePageParam.getSortOrder());
            queryWrapper.orderBy(true, monitorDevicePageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()), StrUtil.toUnderlineCase(monitorDevicePageParam.getSortField()));
        } else {
            queryWrapper.lambda().orderByAsc(MonitorDevice::getSortCode);
        }
        queryWrapper.lambda().eq(MonitorDevice::getCreateOrg,loginUser.getOrgId()).eq(MonitorDevice::getDeleteFlag,CommonDeleteFlagEnum.NOT_DELETE);
        Page<MonitorDevice> page = this.page(CommonPageRequest.defaultPage(), queryWrapper);
        if (page.getTotal() < 1) {
            return page;
        }

        //查询型号编号和名称
        Set<String> codeSet = page.getRecords().stream().map(MonitorDevice::getModelName).filter(StrUtil::isNotBlank).collect(Collectors.toSet());
        List<MonitorDeviceType> deviceTypeList = monitorDeviceTypeService.list(new LambdaQueryWrapper<>(MonitorDeviceType.class)
                .select(MonitorDeviceType::getCode, MonitorDeviceType::getName)
                .in(MonitorDeviceType::getCode, codeSet)
                .eq(MonitorDeviceType::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        Map<String, String> typeNameMap = deviceTypeList.stream().collect(Collectors.toMap(MonitorDeviceType::getCode, MonitorDeviceType::getName));

        //查询使用的路数
        Set<String> deviceIdSet = page.getRecords().stream().map(MonitorDevice::getId).collect(Collectors.toSet());
        List<MonitorTargetRegion> regionList = monitorTargetRegionService.list(new LambdaQueryWrapper<>(MonitorTargetRegion.class)
                .in(MonitorTargetRegion::getMonitorDeviceId, deviceIdSet)
                .eq(MonitorTargetRegion::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        Map<String, List<MonitorTargetRegion>> regionMap = regionList.stream().collect(Collectors.groupingBy(MonitorTargetRegion::getMonitorDeviceId));

        List<MonitorDevicePageDto> dtoList = new ArrayList<>();
        for (MonitorDevice record : page.getRecords()) {
            MonitorDevicePageDto dto = BeanUtil.copyProperties(record, MonitorDevicePageDto.class);
            dto.setCreateOrgName(loginUser.getOrgName());
            dto.setTypeName(typeNameMap.get(record.getModelName()));
            if (regionMap.containsKey(record.getId())) {
                String desc = regionMap.get(record.getId())
                        .stream()
                        .filter(x -> x.getSensorRoute() != null)
                        .map(x -> x.getSensorRoute() + "路")
                        .collect(Collectors.joining("，"));
                dto.setSensorRouteDesc(desc);
            }
            dtoList.add(dto);
        }

        Page<MonitorDevicePageDto> dtoPage = Page.of(page.getCurrent(), page.getSize(), page.getTotal());
        dtoPage.setRecords(dtoList);
        return dtoPage;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void add(MonitorDeviceAddParam monitorDeviceAddParam) {
        // 转换参数
        MonitorDevice monitorDevice = BeanUtil.toBean(monitorDeviceAddParam, MonitorDevice.class);
        // 检查设备编码是否已注册
        if (this.getByDeviceCode(monitorDevice.getDeviceCode())) {
            throw new CommonException("设备编码已注册使用：{}", monitorDevice.getDeviceCode());
        }
        if (this.getByDeviceName(monitorDevice.getDeviceName())) {
            throw new CommonException("设备名已注册使用：{}", monitorDevice.getDeviceName());
        }
        // 保存设备
        boolean save = this.save(monitorDevice);
        // 召唤设备默认参数
        if (save) {
            MonitorDeviceType monitorDeviceType = monitorDeviceTypeService.getByModelName(monitorDevice.getModelName());
            if (monitorDeviceType.getName().equals(MonitorDeviceTypeEnum.RENKE.toString())) {
                try {
                    // 调用设备配置参数接口
                    renKeService.callParamIds(Integer.parseInt(monitorDevice.getDeviceCode()));
                } catch (NumberFormatException e) {
                    // 如果设备编码不能解析为整数，抛出异常或记录日志
                throw new CommonException("设备编码解析失败，无法发送配置参数。设备编码: " + monitorDevice.getDeviceCode(), e + "请输入整数编码");
                }
            }
        } else {
            throw new CommonException("设备保存失败，设备编码: " + monitorDevice.getDeviceCode());
        }
        //缓存整形的设备编号和设备型号到缓存
        monitorDeviceCache.cacheDevice(monitorDevice.getDeviceCode(), monitorDevice.getModelName());
        jfcloudRedisCacheService.evictMonitorDeviceCache();
    }

    public boolean getByDeviceName(String deviceName) {
        List<MonitorDevice> devices = this.list(new LambdaQueryWrapper<MonitorDevice>()
                .eq(MonitorDevice::getDeviceName, deviceName).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        return !devices.isEmpty();
    }


    public boolean getByDeviceCode(String deviceCode) {
        List<MonitorDevice> devices = this.list(new QueryWrapper<MonitorDevice>().eq("device_code", deviceCode)
                .lambda().eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        return !devices.isEmpty() ? true : false;
    }

    public List<MonitorDevice> getDeviceByDeviceName(String deviceName) {
        return this.list(new LambdaQueryWrapper<MonitorDevice>()
                .eq(MonitorDevice::getDeviceName, deviceName).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
    }

    public List<MonitorDevice> getDeviceByDeviceCode(String deviceCode) {
        return this.list(new QueryWrapper<MonitorDevice>().eq("device_code", deviceCode)
                .lambda().eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public void edit(MonitorDeviceEditParam monitorDeviceEditParam) {
        MonitorDevice monitorDevice = this.queryEntity(monitorDeviceEditParam.getId());
        BeanUtil.copyProperties(monitorDeviceEditParam, monitorDevice);
        List<MonitorDevice> deviceByDeviceName = this.getDeviceByDeviceName(monitorDevice.getDeviceName());
        for (MonitorDevice device : deviceByDeviceName) {
            if (!device.getId().equals(monitorDeviceEditParam.getId())) {
                throw new CommonException("设备名已注册使用：{}", monitorDevice.getDeviceName());
            }
        }
        List<MonitorDevice> deviceByDeviceCode = this.getDeviceByDeviceCode(monitorDevice.getDeviceCode());
        for (MonitorDevice device : deviceByDeviceCode) {
            if (!device.getId().equals(monitorDeviceEditParam.getId())) {
                throw new CommonException("设备编码已注册使用：{}", monitorDevice.getDeviceCode());
            }
        }
        boolean update = this.updateById(monitorDevice);
        // 召唤设备默认参数
        if (update) {
            try {
                // 调用设备配置参数接口
                jfcloudRedisCacheService.evictMonitorDeviceCache();
                renKeService.callParamIds(Integer.parseInt(monitorDevice.getDeviceCode()));
            } catch (NumberFormatException e) {
                // 如果设备编码不能解析为整数，抛出异常或记录日志
//                throw new CommonException("设备编码解析失败，无法发送配置参数。设备编码: " + monitorDevice.getDeviceCode(), e + "请输入整数编码");
            }
        } else {
            throw new CommonException("设备保存失败，设备编码: " + monitorDevice.getDeviceCode());
        }
        //缓存整形的设备编号和设备型号到缓存
        monitorDeviceCache.cacheDevice(monitorDevice.getDeviceCode(), monitorDevice.getModelName());
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void delete(List<MonitorDeviceIdParam> monitorDeviceIdParamList) {
        for (MonitorDeviceIdParam monitorDeviceIdParam : monitorDeviceIdParamList) {
            MonitorDevice monitorDevice = queryEntity(monitorDeviceIdParam.getId());
            List<String> targetIdListByDeviceIdList = monitorTargetRegionService.getTargetIdListByDeviceId(monitorDevice.getDeviceCode());
            if (!targetIdListByDeviceIdList.isEmpty()) {
                throw new CommonException("该采集器已被使用，请先删除该采集器下的监测点");
            }
        }
        // 执行删除
        this.removeByIds(CollStreamUtil.toList(monitorDeviceIdParamList, MonitorDeviceIdParam::getId));
        jfcloudRedisCacheService.evictMonitorDeviceCache();
    }

    @Override
    public MonitorDevice detail(MonitorDeviceIdParam monitorDeviceIdParam) {
        return this.queryEntity(monitorDeviceIdParam.getId());
    }

    @Override
    public MonitorDevice queryEntity(String id) {
        MonitorDevice monitorDevice = this.getById(id);
        if (ObjectUtil.isEmpty(monitorDevice)) {
            throw new CommonException("采集器管理不存在，id值为：{}", id);
        }
        return monitorDevice;
    }

    @Override
    public boolean updateParamIds(ParamIdsData data) {
        int deviceId = data.getDeviceId();
        MonitorDevice device = this.getOne(new QueryWrapper<MonitorDevice>().like("device_code", deviceId)
                .lambda().eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        if (device != null) {
            List<Integer> pararmIdList = data.getPararmIdList();
            if (!pararmIdList.isEmpty()) {
                device.setParamIds(pararmIdList);
            }
        }
        return this.updateById(device);
    }

    @Override
    public boolean updateParameters(ParamData data) {
        int deviceId = data.getDeviceId();
        MonitorDevice device = this.getOne(new QueryWrapper<MonitorDevice>().like("device_code", deviceId)
                .lambda().eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        if (device != null && !data.getParameterList().isEmpty()) {
            if (!data.getParameterList().isEmpty()) {
                device.setParameters(data.getParameterList());
            }
        }
        return this.updateById(device);
    }

    @Override
    public boolean updateLastHeartbeatTimeByDeviceId(Integer deviceId, Date timestamp) {
        return updateDeviceTimeByDeviceId(deviceId, timestamp, "lastHeartbeatTime");
    }

    @Override
    public boolean updateLastLoginTimeByDeviceId(Integer deviceId, Date timestamp) {
        return updateDeviceTimeByDeviceId(deviceId, timestamp, "lastLoginTime");
    }


    @Override
    public List<MonitorDevice> myList(Boolean isAll, String sensorType) {
        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();

        //查询设备类型
        LambdaQueryWrapper<MonitorDeviceType> typeQueryWrapper = new LambdaQueryWrapper<>(MonitorDeviceType.class)
                .eq(StrUtil.isNotBlank(sensorType), MonitorDeviceType::getSensorType, sensorType)
                .eq(MonitorDeviceType::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
        List<MonitorDeviceType> deviceTypeList = monitorDeviceTypeService.list(typeQueryWrapper);
        List<String> modelNameList = deviceTypeList.stream().map(MonitorDeviceType::getCode).toList();

        //查询设备列表
        LambdaQueryWrapper<MonitorDevice> deviceQueryWrapper = new LambdaQueryWrapper<>();
        deviceQueryWrapper.in(MonitorDevice::getModelName,modelNameList);
        deviceQueryWrapper.eq(MonitorDevice::getCreateOrg,loginUser.getOrgId()).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
        if (!isAll) {
            deviceQueryWrapper.eq(MonitorDevice::getStatus, MonitorDeviceStatusEnum.NORMAL.getValue())
                    .orderByAsc(MonitorDevice::getSortCode);
        }
        return this.list(deviceQueryWrapper);
    }

    // 通用更新方法，避免代码重复，并处理 timestamp 为空的情况

    private boolean updateDeviceTimeByDeviceId(Integer deviceId, Date timestamp, String timeField) {
        if (timestamp == null) {
            // 如果 timestamp 为空，使用当前系统时间
            timestamp = new Date();  // 或者 new Date(System.currentTimeMillis());
        }
        MonitorDevice device = this.getOne(new QueryWrapper<MonitorDevice>().eq("device_code", deviceId)
                .lambda().eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE));
        if (device == null) {
            // 设备未找到，记录日志
            log.warn("Device with deviceId {} not found", deviceId);
            return false;
        }
        // 根据传入的字段名动态设置时间
        if ("lastHeartbeatTime".equals(timeField)) {
            device.setLastHeartbeatTime(timestamp);
        } else if ("lastLoginTime".equals(timeField)) {
            device.setLastLoginTime(timestamp);
        } else {
            log.error("Invalid time field: {}", timeField);
            return false;
        }
        // 更新设备信息
        return this.updateById(device);
    }

    @Override
    public List<SensorData> queryDataByDeviceIdAndRoads(String deviceId, Integer roads, String startTime, String endTime, String field, AggregationWindow aggregationWindow) {
        return sensorDataService.queryDataByDeviceIdAndRoads(deviceId, roads, startTime, endTime, field, aggregationWindow);
    }

    @Override
    public SensorData queryLatestDataByDeviceIdAndRoads(String deviceId, Integer roads) {
        return sensorDataService.queryLatestDataByDeviceIdAndRoads(deviceId, roads);
    }

    @Override
    public List<SensorData> querySensorData(String deviceId, int roads, Instant startTime, Instant endTime, List<QueryCondition> queryConditions) {
//        return sensorDataService.querySensorData(deviceId, roads, startTime, endTime, queryConditions);
        return null;
    }

    @Override
    public CountEntity getIndexCount() {
        TargetStatus targetCount = monitorTargetService.getTargetCount(null,null);
        CountEntity countEntity = new CountEntity();
        countEntity.setDeviceCount((int) targetCount.getTotal());
//        LambdaQueryWrapper<MonitorDevice> onlineDeviceQueryWrapper = new LambdaQueryWrapper<>();
//        onlineDeviceQueryWrapper.eq(MonitorDevice::getStatus, MonitorDeviceStatusEnum.NORMAL.getValue()).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
//        LambdaQueryWrapper<MonitorDevice> offlineDeviceIdQueryWrapper = new LambdaQueryWrapper<>();
//        offlineDeviceIdQueryWrapper.eq(MonitorDevice::getStatus, MonitorDeviceStatusEnum.UNUSED.getValue()).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
        countEntity.setOnlineDeviceCount((int) targetCount.getOnline());
        countEntity.setOfflineDeviceCount((int) targetCount.getOffline());
        Integer sensorCount = 0;
        SaBaseLoginUser loginUser = StpLoginUserUtil.getLoginUser();
        LambdaQueryWrapper<MonitorDevice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE).eq(MonitorDevice::getCreateOrg, loginUser.getOrgId());
        List<MonitorDevice> monitorDeviceList = list(queryWrapper);
        for (MonitorDevice monitorDevice : monitorDeviceList) {
            sensorCount += monitorDevice.getSensorCount();
        }
        countEntity.setSensorCount(sensorCount);
        countEntity.setUsedSensorCount(monitorTargetRegionService.getUsedSensorCount());
        countEntity.setUnusedSensorCount(sensorCount - countEntity.getUsedSensorCount());
        return countEntity;
    }

    @Override
    public MonitorDevice queryByDeviceCode(Integer deviceId) {
        LambdaQueryWrapper<MonitorDevice> onlineDeviceQueryWrapper = new LambdaQueryWrapper<>();
        onlineDeviceQueryWrapper.eq(MonitorDevice::getDeviceCode, deviceId).eq(MonitorDevice::getDeleteFlag, CommonDeleteFlagEnum.NOT_DELETE);
        return this.getOne(onlineDeviceQueryWrapper);
    }

    @Override
    public void downloadTemplate(HttpServletResponse response) {
        String fileName = "冷链设备导入模板";
        String sheetName = "冷链设备导入模板";
        /*try {
//            ExcelUtil.writeExcel(response, null, fileName, sheetName, MonitorDeviceTemplate.class);
            //表头样式
            WriteCellStyle headWriteCellStyle = new WriteCellStyle();
            //设置表头居中对齐
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
            //内容样式
            WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
            //设置内容靠左对齐
            contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT);

            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("utf8");
            response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + ".xlsx");

            HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
            EasyExcel.write(response.getOutputStream(), MonitorDeviceTemplate.class)
                    .excelType(ExcelTypeEnum.XLSX).sheet(sheetName)
                    .registerWriteHandler(horizontalCellStyleStrategy)
                    .doWrite(new ArrayList<MonitorDeviceTemplate>());
        } catch (Exception e) {
            throw new RuntimeException(e);
        }*/
//        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");

        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + URLEncoder.encode(fileName, StandardCharsets.UTF_8) + ".xls");
        //模板实体类
        List<MonitorDeviceTemplate> secondInspProbExcelDTOS = new ArrayList<>();
        //普通下拉数据
        Map<Integer, String[]> map = ordinarySelect();
        try (OutputStream outputStream = response.getOutputStream()) {
            EasyExcel.write(outputStream, MonitorDeviceTemplate.class)
                    .registerWriteHandler(new CustomCellWriteHandler(map))
                    .excelType(ExcelTypeEnum.XLS)
                    .sheet(sheetName)
                    .doWrite(secondInspProbExcelDTOS);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 普通下拉数据
     *
     * @return
     */
    private Map<Integer, String[]> ordinarySelect() {
        Map<Integer, String[]> map = new HashMap<>();

        List<MonitorDeviceType> list = monitorDeviceTypeService.list();
        List<String> billingNameList = list.stream().map(MonitorDeviceType::getCode).toList();
        map.put(0, billingNameList.toArray(new String[0]));
        return map;
    }
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void importMonitorDevice(MultipartFile file) {
        List<MonitorDeviceTemplate> monitorDeviceTemplateList = null;
        // excel同步读取数据
        try {
            monitorDeviceTemplateList = EasyExcel.read(new BufferedInputStream(file.getInputStream())).head(MonitorDeviceTemplate.class).sheet().doReadSync();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // 检查是否大于1000条
        if (monitorDeviceTemplateList.size() > 1000) {
            throw new RuntimeException("超过最多处理条数");
        }
        List<MonitorDeviceAddParam> monitorDeviceList = new ArrayList<>();
        for (MonitorDeviceTemplate monitorDeviceTemplate : monitorDeviceTemplateList) {
            MonitorDeviceType monitorDeviceType = monitorDeviceTypeService.getByModelName(monitorDeviceTemplate.getModelName());
            if (StrUtil.isBlank(monitorDeviceTemplate.getDeviceName()) && StrUtil.isBlank(monitorDeviceTemplate.getModelName())
            && StrUtil.isBlank(monitorDeviceTemplate.getDeviceCode())) {
                throw new CommonException("设备：*" + monitorDeviceTemplate.getDeviceName() + "*包含未填的必填项");
            }
            // 判断上下限输入是否合法
            if (!Objects.isNull(monitorDeviceTemplate.getTemperatureUp()) && !Objects.isNull(monitorDeviceTemplate.getTemperatureDown())) {
                if (monitorDeviceTemplate.getTemperatureDown() >= monitorDeviceTemplate.getTemperatureUp()) {
                    throw new CommonException("设备：*" + monitorDeviceTemplate.getDeviceName() + "*的温度上下限填写有误");
                }
            } else {
                monitorDeviceTemplate.setTemperatureUp(monitorDeviceType.getTemperatureUp());
                monitorDeviceTemplate.setTemperatureDown(monitorDeviceType.getTemperatureDown());
            }
            if (!Objects.isNull(monitorDeviceTemplate.getHumidityUp()) && !Objects.isNull(monitorDeviceTemplate.getHumidityDown())) {
                if (monitorDeviceTemplate.getHumidityDown() >= monitorDeviceTemplate.getHumidityUp()) {
                    throw new CommonException("设备：*" + monitorDeviceTemplate.getDeviceName() + "*的湿度上下限填写有误");
                }
            } else {
                monitorDeviceTemplate.setHumidityUp(monitorDeviceType.getHumidityUp());
                monitorDeviceTemplate.setHumidityDown(monitorDeviceType.getHumidityDown());
            }
            if (!Objects.isNull(monitorDeviceTemplate.getCo2Up()) && !Objects.isNull(monitorDeviceTemplate.getCo2Down())) {
                if (monitorDeviceTemplate.getCo2Down() >= monitorDeviceTemplate.getCo2Up()) {
                    throw new CommonException("设备：*" + monitorDeviceTemplate.getDeviceName() + "*的二氧化碳上下限填写有误");
                }
            } else {
                monitorDeviceTemplate.setCo2Up(monitorDeviceType.getCo2Up());
                monitorDeviceTemplate.setCo2Down(monitorDeviceType.getCo2Down());
            }
            MonitorDeviceAddParam monitorDevice = BeanUtil.copyProperties(monitorDeviceTemplate, MonitorDeviceAddParam.class);
            monitorDevice.setSensorCount(monitorDeviceType.getSensorCount());
            monitorDeviceList.add(monitorDevice);
        }
        // 入库操作
        monitorDeviceList.forEach(this::add);
    }

    @Override
    @Cacheable(value = JfcloudColdChainConstants.MONITORDEVICE_CACHE_NAME, unless = "#result == null")
    public Set<String> getAllDeviceCodes() {
        // 构建查询条件，查询 modelName 以 "RS" 开头的设备
        LambdaQueryWrapper<MonitorDevice> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.likeRight(MonitorDevice::getModelName, "RS");
        queryWrapper.select(MonitorDevice::getDeviceCode);  // 只查询 deviceCode 字段
        List<MonitorDevice> deviceList = this.list(queryWrapper);
        // 提取 deviceCode 字段并收集到 Set<String> 中
        return deviceList.stream()
                .map(MonitorDevice::getDeviceCode)  // 提取 deviceCode 字段
                .collect(Collectors.toSet());      // 收集到 Set 中去重
    }

}
