package com.zksy.base.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zksy.base.alarm.mapper.AlarmDataMapper;
import com.zksy.base.audio.domain.NoiseInfo;
import com.zksy.base.audio.mapper.NoiseInfoMapper;
import com.zksy.base.domain.EquipmentBase;
import com.zksy.base.domain.EquipmentMaintain;
import com.zksy.base.domain.EquipmentStatus;
import com.zksy.base.domain.EquipmentType;
import com.zksy.base.domain.vo.*;
import com.zksy.base.environment.domain.ERealTimeData;
import com.zksy.base.environment.mapper.ERealTimeDataMapper;
import com.zksy.base.gas.domain.GasMonitorData;
import com.zksy.base.gas.mapper.GasMonitorDataMapper;
import com.zksy.base.mapper.EquipmentBaseMapper;
import com.zksy.base.mapper.EquipmentMaintainMapper;
import com.zksy.base.mapper.EquipmentStatusMapper;
import com.zksy.base.mapper.EquipmentTypeMapper;
import com.zksy.base.pressure.domain.FirefightingPressure;
import com.zksy.base.pressure.mapper.FirefightingPressureMapper;
import com.zksy.base.radar.domain.RadarData;
import com.zksy.base.radar.mapper.RadarDataMapper;
import com.zksy.base.service.WaterSupplyDeviceService;
import com.zksy.base.telemetry.domain.TelemetryData;
import com.zksy.base.telemetry.mapper.TelemetryDataMapper;
import com.zksy.base.water.domain.WaterMonitorData;
import com.zksy.base.water.mapper.WaterMonitorDataMapper;
import com.zksy.common.sms.SmsTemplate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class WaterSupplyDeviceServiceImpl extends ServiceImpl<EquipmentBaseMapper, EquipmentBase>
        implements WaterSupplyDeviceService {

    @Autowired
    private EquipmentTypeMapper equipmentTypeMapper;

    @Autowired
    private EquipmentStatusMapper equipmentStatusMapper;

    @Autowired
    private EquipmentMaintainMapper equipmentMaintainMapper;

    @Autowired
    private RadarDataMapper radarDataMapper;

    @Autowired
    private WaterMonitorDataMapper waterMonitorDataMapper;

    @Autowired
    private TelemetryDataMapper telemetryDataMapper;

    @Autowired
    private GasMonitorDataMapper gasMonitorDataMapper;

    @Autowired
    private FirefightingPressureMapper firefightingPressureMapper;

    @Autowired
    private ERealTimeDataMapper eRealTimeDataMapper;

    @Autowired
    private NoiseInfoMapper noiseInfoMapper;

    @Autowired
    private AlarmDataMapper alarmDataMapper;

    @Autowired(required = false)
    private SmsTemplate smsTemplate;

    @Override
    public List<DeviceTypeStatisticsVO> getDeviceTypeStatistics() {
        List<EquipmentType> allTypes = equipmentTypeMapper.selectList(
                new LambdaQueryWrapper<EquipmentType>().orderByAsc(EquipmentType::getTypeId)
        );
        if (CollUtil.isEmpty(allTypes)) {
            return new ArrayList<>();
        }

        List<EquipmentBase> allDevices = this.list(
                new LambdaQueryWrapper<EquipmentBase>()
                        .select(EquipmentBase::getEquipmentId, EquipmentBase::getEquipmentTypeId)
        );
        Map<String, Long> typeCountMap = allDevices.stream()
                .filter(d -> d.getEquipmentTypeId() != null)
                .collect(Collectors.groupingBy(EquipmentBase::getEquipmentTypeId, Collectors.counting()));

        Map<String, DeviceTypeStatisticsVO> voMap = new HashMap<>();
        for (EquipmentType type : allTypes) {
            DeviceTypeStatisticsVO vo = new DeviceTypeStatisticsVO();
            vo.setTypeId(type.getTypeId());
            vo.setTypeName(type.getTypeName());
            vo.setParentTypeId(type.getParentTypeId());
            vo.setDeviceCount(typeCountMap.getOrDefault(type.getTypeId(), 0L).intValue());
            vo.setChildren(new ArrayList<>());
            voMap.put(type.getTypeId(), vo);
        }

        List<DeviceTypeStatisticsVO> roots = new ArrayList<>();
        for (DeviceTypeStatisticsVO vo : voMap.values()) {
            String parentId = vo.getParentTypeId();
            if (parentId == null || "0".equals(parentId) || !voMap.containsKey(parentId)) {
                roots.add(vo);
            } else {
                voMap.get(parentId).getChildren().add(vo);
            }
        }

        calculateTotalCount(roots);
        return roots;
    }

    private int calculateTotalCount(List<DeviceTypeStatisticsVO> list) {
        int total = 0;
        for (DeviceTypeStatisticsVO vo : list) {
            int childCount = 0;
            if (CollUtil.isNotEmpty(vo.getChildren())) {
                childCount = calculateTotalCount(vo.getChildren());
            }
            total += vo.getDeviceCount() + childCount;
            vo.setDeviceCount(vo.getDeviceCount() + childCount);
        }
        return total;
    }

    @Override
    public Page<DeviceGisVO> getDeviceLedgerPage(long pageNum, long pageSize,
                                                  String equipmentName, String equipmentCode,
                                                  String equipmentTypeId, Integer status) {
        Page<EquipmentBase> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<EquipmentBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotBlank(equipmentName), EquipmentBase::getEquipmentName, equipmentName)
                .like(StrUtil.isNotBlank(equipmentCode), EquipmentBase::getEquipmentCode, equipmentCode)
                .eq(StrUtil.isNotBlank(equipmentTypeId), EquipmentBase::getEquipmentTypeId, equipmentTypeId)
                .orderByDesc(EquipmentBase::getCreateTime);
        Page<EquipmentBase> basePage = this.page(page, wrapper);

        Page<DeviceGisVO> resultPage = new Page<>(pageNum, pageSize, basePage.getTotal());
        if (CollUtil.isEmpty(basePage.getRecords())) {
            resultPage.setRecords(new ArrayList<>());
            return resultPage;
        }

        List<EquipmentBase> records = basePage.getRecords();
        List<String> equipmentIds = records.stream().map(EquipmentBase::getEquipmentId).collect(Collectors.toList());

        Map<String, EquipmentStatus> statusMap = getStatusMap(equipmentIds);
        Map<String, EquipmentType> typeMap = getTypeMap(records);

        List<DeviceGisVO> voList = new ArrayList<>();
        for (EquipmentBase base : records) {
            DeviceGisVO vo = BeanUtil.copyProperties(base, DeviceGisVO.class);
            EquipmentStatus es = statusMap.get(base.getEquipmentId());
            if (es != null) {
                vo.setOnlineStatus(es.getOnlineStatus());
                vo.setAlarmStatus(es.getAlarmStatus());
                vo.setCurrentStatus(es.getCurrentStatus());
            }
            EquipmentType et = typeMap.get(base.getEquipmentTypeId());
            if (et != null) {
                vo.setEquipmentTypeName(et.getTypeName());
            }
            fillGpsFields(vo, base.getLongitude(), base.getLatitude());
            voList.add(vo);
        }
        resultPage.setRecords(voList);
        return resultPage;
    }

    @Override
    public List<DeviceGisVO> getAllDeviceGisPoints(String equipmentTypeId) {
        LambdaQueryWrapper<EquipmentBase> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(equipmentTypeId), EquipmentBase::getEquipmentTypeId, equipmentTypeId)
                .isNotNull(EquipmentBase::getLongitude)
                .isNotNull(EquipmentBase::getLatitude);
        List<EquipmentBase> list = this.list(wrapper);
        if (CollUtil.isEmpty(list)) {
            return new ArrayList<>();
        }

        List<String> equipmentIds = list.stream().map(EquipmentBase::getEquipmentId).collect(Collectors.toList());
        Map<String, EquipmentStatus> statusMap = getStatusMap(equipmentIds);
        Map<String, EquipmentType> typeMap = getTypeMap(list);

        List<DeviceGisVO> result = new ArrayList<>();
        for (EquipmentBase base : list) {
            DeviceGisVO vo = BeanUtil.copyProperties(base, DeviceGisVO.class);
            EquipmentStatus es = statusMap.get(base.getEquipmentId());
            if (es != null) {
                vo.setOnlineStatus(es.getOnlineStatus());
                vo.setAlarmStatus(es.getAlarmStatus());
                vo.setCurrentStatus(es.getCurrentStatus());
            }
            EquipmentType et = typeMap.get(base.getEquipmentTypeId());
            if (et != null) {
                vo.setEquipmentTypeName(et.getTypeName());
            }
            fillGpsFields(vo, base.getLongitude(), base.getLatitude());
            result.add(vo);
        }
        return result;
    }

    @Override
    public DeviceDetailVO getDeviceDetail(String equipmentId) {
        EquipmentBase base = this.getById(equipmentId);
        if (base == null) {
            return null;
        }

        DeviceDetailVO vo = BeanUtil.copyProperties(base, DeviceDetailVO.class);
        EquipmentType type = equipmentTypeMapper.selectById(base.getEquipmentTypeId());
        if (type != null) {
            vo.setEquipmentTypeName(type.getTypeName());
        }

        EquipmentStatus status = equipmentStatusMapper.selectOne(
                new LambdaQueryWrapper<EquipmentStatus>().eq(EquipmentStatus::getEquipmentId, equipmentId)
        );
        if (status != null) {
            vo.setOnlineStatus(status.getOnlineStatus());
            vo.setAlarmStatus(status.getAlarmStatus());
            vo.setCurrentStatus(status.getCurrentStatus());
        }

        fillGpsFields(vo, base.getLongitude(), base.getLatitude());

        Map<String, Object> latestData = getLatestMonitorData(base.getEquipmentCode(), base.getEquipmentTypeId());
        vo.setLatestData(latestData);
        if (latestData != null && latestData.containsKey("createTime")) {
            vo.setLastDataTime((LocalDateTime) latestData.get("createTime"));
        }

        EquipmentMaintain latestMaintain = equipmentMaintainMapper.selectOne(
                new LambdaQueryWrapper<EquipmentMaintain>()
                        .eq(EquipmentMaintain::getEquipmentId, equipmentId)
                        .orderByDesc(EquipmentMaintain::getMaintainDate)
                        .last("LIMIT 1")
        );
        if (latestMaintain != null) {
            Map<String, Object> maintainMap = new HashMap<>();
            maintainMap.put("maintainId", latestMaintain.getMaintainId());
            maintainMap.put("maintainType", latestMaintain.getMaintainType());
            maintainMap.put("maintainContent", latestMaintain.getMaintainContent());
            maintainMap.put("maintainPerson", latestMaintain.getMaintainPerson());
            maintainMap.put("maintainDate", latestMaintain.getMaintainDate());
            vo.setLatestMaintain(maintainMap);
        }

        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean createMaintainOrder(MaintainOrderVO vo) {
        EquipmentBase device = this.getById(vo.getEquipmentId());
        if (device == null) {
            throw new RuntimeException("设备不存在：" + vo.getEquipmentId());
        }

        EquipmentMaintain maintain = new EquipmentMaintain();
        maintain.setEquipmentId(vo.getEquipmentId());
        maintain.setMaintainType(StrUtil.isNotBlank(vo.getMaintainType()) ? vo.getMaintainType() : "故障维修");
        maintain.setMaintainContent(vo.getMaintainContent());
        maintain.setMaintainPerson(vo.getMaintainPerson());
        maintain.setMaintainPersonPhone(vo.getMaintainPersonPhone());
        maintain.setMaintainCost(vo.getMaintainCost());
        maintain.setMaintainRemark(vo.getMaintainRemark());
        int insert = equipmentMaintainMapper.insert(maintain);

        if (insert > 0) {
            EquipmentStatus status = equipmentStatusMapper.selectOne(
                    new LambdaQueryWrapper<EquipmentStatus>().eq(EquipmentStatus::getEquipmentId, vo.getEquipmentId())
            );
            if (status != null) {
                status.setCurrentStatus(3);
                status.setStatusUpdateTime(LocalDateTime.now());
                equipmentStatusMapper.updateById(status);
            } else {
                EquipmentStatus newStatus = new EquipmentStatus();
                newStatus.setEquipmentId(vo.getEquipmentId());
                newStatus.setCurrentStatus(3);
                newStatus.setAlarmStatus(0);
                newStatus.setOnlineStatus(1);
                newStatus.setStatusUpdateTime(LocalDateTime.now());
                newStatus.setCreateTime(LocalDateTime.now());
                equipmentStatusMapper.insert(newStatus);
            }
            log.info("设备[{}]派单成功，工单ID：{}，维修人：{}",
                    vo.getEquipmentId(), maintain.getMaintainId(), vo.getMaintainPerson());

            // 发送短信通知维修人员
            sendMaintainSmsNotify(device, maintain);
        }

        return insert > 0;
    }

    private void sendMaintainSmsNotify(EquipmentBase device, EquipmentMaintain maintain) {
        try {
            if (smsTemplate == null) {
                log.debug("短信服务未注入，跳过维修派单短信通知");
                return;
            }
            String phone = null;
            if (maintain.getMaintainPersonPhone() != null) {
                phone = String.valueOf(maintain.getMaintainPersonPhone());
            } else if (device.getMaintainerPhone() != null) {
                phone = device.getMaintainerPhone();
            }
            if (StrUtil.isBlank(phone)) {
                log.warn("维修派单短信通知失败：无维修人手机号，设备={}", device.getEquipmentId());
                return;
            }

            Map<String, Boolean> result = smsTemplate.sendMaintainNotify(
                    Collections.singletonList(phone),
                    device.getEquipmentName(),
                    device.getEquipmentCode(),
                    device.getEquipmentLocation(),
                    maintain.getMaintainContent()
            );
            boolean success = result.values().stream().anyMatch(Boolean::booleanValue);
            log.info("维修派单短信通知结果：设备={}, 维修人={}, 电话={}, 成功={}",
                    device.getEquipmentId(), maintain.getMaintainPerson(), phone, success);
        } catch (Exception e) {
            log.warn("维修派单短信通知异常：{}", e.getMessage());
        }
    }

    @Override
    public Page<AbnormalDeviceVO> getAbnormalDevicePage(long pageNum, long pageSize,
                                                         String equipmentName, String equipmentCode,
                                                         String equipmentTypeId, Integer alertLevel) {
        LambdaQueryWrapper<EquipmentStatus> statusWrapper = new LambdaQueryWrapper<>();
        statusWrapper.and(w -> w.eq(EquipmentStatus::getAlarmStatus, 1)
                .or().eq(EquipmentStatus::getCurrentStatus, 3));

        List<EquipmentStatus> allAbnormalStatus = equipmentStatusMapper.selectList(statusWrapper);
        if (CollUtil.isEmpty(allAbnormalStatus)) {
            Page<AbnormalDeviceVO> emptyPage = new Page<>(pageNum, pageSize, 0);
            emptyPage.setRecords(new ArrayList<>());
            return emptyPage;
        }

        List<String> equipmentIds = allAbnormalStatus.stream()
                .map(EquipmentStatus::getEquipmentId).distinct().collect(Collectors.toList());

        LambdaQueryWrapper<EquipmentBase> baseWrapper = new LambdaQueryWrapper<>();
        baseWrapper.in(EquipmentBase::getEquipmentId, equipmentIds)
                .like(StrUtil.isNotBlank(equipmentName), EquipmentBase::getEquipmentName, equipmentName)
                .like(StrUtil.isNotBlank(equipmentCode), EquipmentBase::getEquipmentCode, equipmentCode)
                .eq(StrUtil.isNotBlank(equipmentTypeId), EquipmentBase::getEquipmentTypeId, equipmentTypeId);

        List<EquipmentBase> allDevices = this.list(baseWrapper);
        if (CollUtil.isEmpty(allDevices)) {
            Page<AbnormalDeviceVO> emptyPage = new Page<>(pageNum, pageSize, 0);
            emptyPage.setRecords(new ArrayList<>());
            return emptyPage;
        }

        int total = allDevices.size();
        int fromIndex = (int) ((pageNum - 1) * pageSize);
        int toIndex = Math.min(fromIndex + (int) pageSize, total);
        List<EquipmentBase> pageDevices = allDevices.subList(fromIndex, toIndex);

        Map<String, EquipmentStatus> statusMap = allAbnormalStatus.stream()
                .collect(Collectors.toMap(EquipmentStatus::getEquipmentId, s -> s, (a, b) -> a));
        Map<String, EquipmentType> typeMap = getTypeMap(pageDevices);
        Map<String, EquipmentMaintain> maintainMap = getLatestMaintainMap(
                pageDevices.stream().map(EquipmentBase::getEquipmentId).collect(Collectors.toList())
        );

        List<AbnormalDeviceVO> voList = new ArrayList<>();
        for (EquipmentBase base : pageDevices) {
            AbnormalDeviceVO vo = BeanUtil.copyProperties(base, AbnormalDeviceVO.class);
            EquipmentStatus es = statusMap.get(base.getEquipmentId());
            if (es != null) {
                vo.setCurrentStatus(es.getCurrentStatus());
                vo.setAlarmStatus(es.getAlarmStatus());
                vo.setOnlineStatus(es.getOnlineStatus());
                vo.setStatusUpdateTime(es.getStatusUpdateTime());
            }
            EquipmentType et = typeMap.get(base.getEquipmentTypeId());
            if (et != null) {
                vo.setEquipmentTypeName(et.getTypeName());
            }
            EquipmentMaintain maintain = maintainMap.get(base.getEquipmentId());
            if (maintain != null) {
                vo.setLatestMaintainId(maintain.getMaintainId());
                vo.setLatestMaintainPerson(maintain.getMaintainPerson());
            }
            vo.setAlertLevel(calcAlertLevel(base.getEquipmentCode(), es));
            fillGpsFields(vo, base.getLongitude(), base.getLatitude());
            voList.add(vo);
        }

        Page<AbnormalDeviceVO> resultPage = new Page<>(pageNum, pageSize, total);
        resultPage.setRecords(voList);
        return resultPage;
    }

    @Override
    public List<AbnormalDeviceVO> getAbnormalDeviceGisPoints(String equipmentTypeId) {
        LambdaQueryWrapper<EquipmentStatus> statusWrapper = new LambdaQueryWrapper<>();
        statusWrapper.and(w -> w.eq(EquipmentStatus::getAlarmStatus, 1)
                .or().eq(EquipmentStatus::getCurrentStatus, 3));
        List<EquipmentStatus> allAbnormalStatus = equipmentStatusMapper.selectList(statusWrapper);
        if (CollUtil.isEmpty(allAbnormalStatus)) {
            return new ArrayList<>();
        }

        List<String> equipmentIds = allAbnormalStatus.stream()
                .map(EquipmentStatus::getEquipmentId).distinct().collect(Collectors.toList());

        LambdaQueryWrapper<EquipmentBase> baseWrapper = new LambdaQueryWrapper<>();
        baseWrapper.in(EquipmentBase::getEquipmentId, equipmentIds)
                .eq(StrUtil.isNotBlank(equipmentTypeId), EquipmentBase::getEquipmentTypeId, equipmentTypeId)
                .isNotNull(EquipmentBase::getLongitude)
                .isNotNull(EquipmentBase::getLatitude);
        List<EquipmentBase> devices = this.list(baseWrapper);
        if (CollUtil.isEmpty(devices)) {
            return new ArrayList<>();
        }

        Map<String, EquipmentStatus> statusMap = allAbnormalStatus.stream()
                .collect(Collectors.toMap(EquipmentStatus::getEquipmentId, s -> s, (a, b) -> a));
        Map<String, EquipmentType> typeMap = getTypeMap(devices);

        List<AbnormalDeviceVO> result = new ArrayList<>();
        for (EquipmentBase base : devices) {
            AbnormalDeviceVO vo = BeanUtil.copyProperties(base, AbnormalDeviceVO.class);
            EquipmentStatus es = statusMap.get(base.getEquipmentId());
            if (es != null) {
                vo.setCurrentStatus(es.getCurrentStatus());
                vo.setAlarmStatus(es.getAlarmStatus());
                vo.setOnlineStatus(es.getOnlineStatus());
            }
            EquipmentType et = typeMap.get(base.getEquipmentTypeId());
            if (et != null) {
                vo.setEquipmentTypeName(et.getTypeName());
            }
            vo.setAlertLevel(calcAlertLevel(base.getEquipmentCode(), es));
            fillGpsFields(vo, base.getLongitude(), base.getLatitude());
            result.add(vo);
        }
        return result;
    }

    @Override
    public List<Map<String, Object>> getMaintainRecordList(String equipmentId) {
        List<EquipmentMaintain> list = equipmentMaintainMapper.selectList(
                new LambdaQueryWrapper<EquipmentMaintain>()
                        .eq(EquipmentMaintain::getEquipmentId, equipmentId)
                        .orderByDesc(EquipmentMaintain::getMaintainDate)
        );
        List<Map<String, Object>> result = new ArrayList<>();
        for (EquipmentMaintain m : list) {
            Map<String, Object> map = new HashMap<>();
            map.put("maintainId", m.getMaintainId());
            map.put("maintainType", m.getMaintainType());
            map.put("maintainContent", m.getMaintainContent());
            map.put("maintainPerson", m.getMaintainPerson());
            map.put("maintainDate", m.getMaintainDate());
            map.put("maintainCost", m.getMaintainCost());
            map.put("maintainRemark", m.getMaintainRemark());
            result.add(map);
        }
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveMaintainRecord(EquipmentMaintainDataVO vo) {
        if (StrUtil.isBlank(vo.getEquipmentId())) {
            throw new RuntimeException("设备ID不能为空");
        }
        EquipmentBase device = this.getById(vo.getEquipmentId());
        if (device == null) {
            throw new RuntimeException("设备不存在");
        }
        EquipmentMaintain maintain = BeanUtil.copyProperties(vo, EquipmentMaintain.class);
        return equipmentMaintainMapper.insert(maintain) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateMaintainRecord(EquipmentMaintainDataVO vo) {
        if (StrUtil.isBlank(vo.getMaintainId())) {
            throw new RuntimeException("维护记录ID不能为空");
        }
        EquipmentMaintain maintain = BeanUtil.copyProperties(vo, EquipmentMaintain.class);
        return equipmentMaintainMapper.updateById(maintain) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteMaintainRecord(String maintainId) {
        return equipmentMaintainMapper.deleteById(maintainId) > 0;
    }

    @Override
    public Page<EquipmentMaintainDataVO> getMaintainRecordPage(long pageNum, long pageSize,
                                                                String equipmentName, String maintainPerson,
                                                                String maintainType, String status,
                                                                String startTime, String endTime) {
        LambdaQueryWrapper<EquipmentMaintain> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(StrUtil.isNotBlank(maintainPerson), EquipmentMaintain::getMaintainPerson, maintainPerson)
                .eq(StrUtil.isNotBlank(maintainType), EquipmentMaintain::getMaintainType, maintainType)
                .orderByDesc(EquipmentMaintain::getMaintainDate);

        Page<EquipmentMaintain> maintainPage = equipmentMaintainMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
        Page<EquipmentMaintainDataVO> resultPage = new Page<>(pageNum, pageSize, maintainPage.getTotal());

        if (CollUtil.isEmpty(maintainPage.getRecords())) {
            resultPage.setRecords(new ArrayList<>());
            return resultPage;
        }

        List<String> equipmentIds = maintainPage.getRecords().stream()
                .map(EquipmentMaintain::getEquipmentId).distinct().collect(Collectors.toList());
        List<EquipmentBase> devices = this.listByIds(equipmentIds);
        Map<String, EquipmentBase> deviceMap = devices.stream()
                .collect(Collectors.toMap(EquipmentBase::getEquipmentId, d -> d, (a, b) -> a));

        List<EquipmentMaintainDataVO> voList = new ArrayList<>();
        for (EquipmentMaintain m : maintainPage.getRecords()) {
            EquipmentMaintainDataVO vo = BeanUtil.copyProperties(m, EquipmentMaintainDataVO.class);
            EquipmentBase device = deviceMap.get(m.getEquipmentId());
            if (device != null) {
                vo.setEquipmentCode(device.getEquipmentCode());
                vo.setEquipmentName(device.getEquipmentName());
                vo.setEquipmentLocation(device.getEquipmentLocation());
                vo.setLongitude(device.getLongitude());
                vo.setLatitude(device.getLatitude());
            }
            if (StrUtil.isNotBlank(equipmentName) && (vo.getEquipmentName() == null
                    || !vo.getEquipmentName().contains(equipmentName))) {
                continue;
            }
            voList.add(vo);
        }
        resultPage.setRecords(voList);
        return resultPage;
    }

    @Override
    public Page<EquipmentMaintainDataVO> getMyMaintainRecordPage(long pageNum, long pageSize,
                                                                   String maintainPerson,
                                                                   String maintainType, String status,
                                                                   String startTime, String endTime) {
        LambdaQueryWrapper<EquipmentMaintain> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(StrUtil.isNotBlank(maintainPerson), EquipmentMaintain::getMaintainPerson, maintainPerson)
                .eq(StrUtil.isNotBlank(maintainType), EquipmentMaintain::getMaintainType, maintainType)
                .orderByDesc(EquipmentMaintain::getMaintainDate);

        Page<EquipmentMaintain> maintainPage = equipmentMaintainMapper.selectPage(new Page<>(pageNum, pageSize), wrapper);
        Page<EquipmentMaintainDataVO> resultPage = new Page<>(pageNum, pageSize, maintainPage.getTotal());

        if (CollUtil.isEmpty(maintainPage.getRecords())) {
            resultPage.setRecords(new ArrayList<>());
            return resultPage;
        }

        List<String> equipmentIds = maintainPage.getRecords().stream()
                .map(EquipmentMaintain::getEquipmentId).distinct().collect(Collectors.toList());
        List<EquipmentBase> devices = this.listByIds(equipmentIds);
        Map<String, EquipmentBase> deviceMap = devices.stream()
                .collect(Collectors.toMap(EquipmentBase::getEquipmentId, d -> d, (a, b) -> a));

        List<EquipmentMaintainDataVO> voList = new ArrayList<>();
        for (EquipmentMaintain m : maintainPage.getRecords()) {
            EquipmentMaintainDataVO vo = BeanUtil.copyProperties(m, EquipmentMaintainDataVO.class);
            EquipmentBase device = deviceMap.get(m.getEquipmentId());
            if (device != null) {
                vo.setEquipmentCode(device.getEquipmentCode());
                vo.setEquipmentName(device.getEquipmentName());
                vo.setEquipmentLocation(device.getEquipmentLocation());
                vo.setLongitude(device.getLongitude());
                vo.setLatitude(device.getLatitude());
            }
            voList.add(vo);
        }
        resultPage.setRecords(voList);
        return resultPage;
    }

    private Map<String, EquipmentStatus> getStatusMap(List<String> equipmentIds) {
        if (CollUtil.isEmpty(equipmentIds)) {
            return new HashMap<>();
        }
        List<EquipmentStatus> statusList = equipmentStatusMapper.selectList(
                new LambdaQueryWrapper<EquipmentStatus>().in(EquipmentStatus::getEquipmentId, equipmentIds)
        );
        return statusList.stream()
                .collect(Collectors.toMap(EquipmentStatus::getEquipmentId, s -> s, (a, b) -> a));
    }

    private Map<String, EquipmentType> getTypeMap(List<EquipmentBase> devices) {
        if (CollUtil.isEmpty(devices)) {
            return new HashMap<>();
        }
        List<String> typeIds = devices.stream()
                .map(EquipmentBase::getEquipmentTypeId)
                .filter(Objects::nonNull).distinct().collect(Collectors.toList());
        if (CollUtil.isEmpty(typeIds)) {
            return new HashMap<>();
        }
        List<EquipmentType> types = equipmentTypeMapper.selectBatchIds(typeIds);
        return types.stream()
                .collect(Collectors.toMap(EquipmentType::getTypeId, t -> t, (a, b) -> a));
    }

    private Map<String, EquipmentMaintain> getLatestMaintainMap(List<String> equipmentIds) {
        if (CollUtil.isEmpty(equipmentIds)) {
            return new HashMap<>();
        }
        List<EquipmentMaintain> allMaintains = equipmentMaintainMapper.selectList(
                new LambdaQueryWrapper<EquipmentMaintain>()
                        .in(EquipmentMaintain::getEquipmentId, equipmentIds)
                        .orderByDesc(EquipmentMaintain::getMaintainDate)
        );
        Map<String, EquipmentMaintain> result = new HashMap<>();
        for (EquipmentMaintain m : allMaintains) {
            if (!result.containsKey(m.getEquipmentId())) {
                result.put(m.getEquipmentId(), m);
            }
        }
        return result;
    }

    private Map<String, Object> getLatestMonitorData(String deviceCode, String equipmentTypeId) {
        if (StrUtil.isBlank(deviceCode) || StrUtil.isBlank(equipmentTypeId)) {
            return new HashMap<>();
        }
        EquipmentType type = equipmentTypeMapper.selectById(equipmentTypeId);
        String typeName = type != null ? type.getTypeName() : "";
        Map<String, Object> result = new HashMap<>();

        try {
            if (typeName.contains("雷达") || typeName.contains("流量")) {
                RadarData data = radarDataMapper.selectOne(
                        new LambdaQueryWrapper<RadarData>()
                                .eq(RadarData::getDeviceCode, deviceCode)
                                .orderByDesc(RadarData::getCreateTime)
                                .last("LIMIT 1")
                );
                if (data != null) {
                    result.put("instantFlow", data.getMeter1InstantFlow());
                    result.put("flowSpeed", data.getFlowSpeed());
                    result.put("waterLevel", data.getWaterLevel());
                    result.put("totalFlow", data.getMeter1NetTotal());
                    result.put("signalQuality", data.getSignalQuality());
                    result.put("createTime", data.getCreateTime());
                    result.put("dataType", "雷达流量计");
                }
            } else if (typeName.contains("水位") || typeName.contains("液位")) {
                WaterMonitorData data = waterMonitorDataMapper.selectOne(
                        new LambdaQueryWrapper<WaterMonitorData>()
                                .eq(WaterMonitorData::getDeviceCode, deviceCode)
                                .orderByDesc(WaterMonitorData::getCreateTime)
                                .last("LIMIT 1")
                );
                if (data != null) {
                    result.put("waterLevel", data.getWaterLevel());
                    result.put("signalQuality", data.getSignalQuality());
                    result.put("createTime", data.getCreateTime());
                    result.put("dataType", "水位计");
                }
            } else if (typeName.contains("遥测")) {
                TelemetryData data = telemetryDataMapper.selectOne(
                        new LambdaQueryWrapper<TelemetryData>()
                                .eq(TelemetryData::getDeviceCode, deviceCode)
                                .orderByDesc(TelemetryData::getCreateTime)
                                .last("LIMIT 1")
                );
                if (data != null) {
                    result.put("positiveTotal", data.getMeter1PositiveTotal());
                    result.put("instantFlow", data.getMeter1InstantFlow());
                    result.put("flowSpeed", data.getFlowSpeed());
                    result.put("pressure", data.getPressure());
                    result.put("temperature", data.getTemperature());
                    result.put("signalQuality", data.getSignalQuality());
                    result.put("createTime", data.getCreateTime());
                    result.put("dataType", "遥测终端");
                }
            } else if (typeName.contains("燃气") || typeName.contains("气体")) {
                GasMonitorData data = gasMonitorDataMapper.selectOne(
                        new LambdaQueryWrapper<GasMonitorData>()
                                .eq(GasMonitorData::getMacAddress, deviceCode)
                                .orderByDesc(GasMonitorData::getCreateTime)
                                .last("LIMIT 1")
                );
                if (data != null) {
                    result.put("gasConcentration", data.getGasConcentration());
                    result.put("gasType", data.getGasType());
                    result.put("battery", data.getBattery());
                    result.put("signalStrength", data.getSignalStrength());
                    result.put("createTime", data.getCreateTime());
                    result.put("dataType", "燃气监测");
                }
            } else if (typeName.contains("压力") || typeName.contains("消防")) {
                FirefightingPressure data = firefightingPressureMapper.selectOne(
                        new LambdaQueryWrapper<FirefightingPressure>()
                                .eq(FirefightingPressure::getTelemeteringStation, deviceCode)
                                .orderByDesc(FirefightingPressure::getSendingTime)
                                .last("LIMIT 1")
                );
                if (data != null) {
                    result.put("pressureValue", data.getPressureValue());
                    result.put("gprsSignal", data.getGprsSignal());
                    result.put("hostVoltage", data.getHostVoltage());
                    result.put("createTime", data.getSendingTime());
                    result.put("dataType", "压力监测");
                }
            } else if (typeName.contains("环境") || typeName.contains("水质")) {
                try {
                    Integer devId = Integer.parseInt(deviceCode);
                    ERealTimeData data = eRealTimeDataMapper.selectOne(
                            new LambdaQueryWrapper<ERealTimeData>()
                                    .eq(ERealTimeData::getDeviceId, devId)
                                    .orderByDesc(ERealTimeData::getCreateTime)
                                    .last("LIMIT 1")
                    );
                    if (data != null) {
                        result.put("temperature", data.getTem());
                        result.put("humidity", data.getHum());
                        result.put("lng", data.getLng());
                        result.put("lat", data.getLat());
                        result.put("createTime", data.getCreateTime());
                        result.put("dataType", "环境监测");
                    }
                } catch (NumberFormatException e) {
                    log.debug("环境设备编码不是数字类型：{}", deviceCode);
                }
            } else if (typeName.contains("噪声") || typeName.contains("音频")) {
                NoiseInfo data = noiseInfoMapper.selectOne(
                        new LambdaQueryWrapper<NoiseInfo>()
                                .eq(NoiseInfo::getEncode, deviceCode)
                                .orderByDesc(NoiseInfo::getCreateTime)
                                .last("LIMIT 1")
                );
                if (data != null) {
                    result.put("rms", data.getRms());
                    result.put("power", data.getPower());
                    result.put("gain", data.getGain());
                    result.put("centerFrequency", data.getCenterFrequency());
                    result.put("filepath", data.getFilepath());
                    result.put("createTime", data.getCreateTime());
                    result.put("dataType", "噪声监测");
                }
            } else {
                result.put("dataType", "未知类型");
            }
        } catch (Exception e) {
            log.warn("获取设备[{}]最新监测数据异常：{}", deviceCode, e.getMessage());
            result.put("dataType", "暂无数据");
        }
        return result;
    }

    private int calcAlertLevel(String deviceCode, EquipmentStatus status) {
        if (status == null || status.getAlarmStatus() == null || status.getAlarmStatus() == 0) {
            if (status != null && status.getCurrentStatus() != null && status.getCurrentStatus() == 3) {
                return 3;
            }
            return 4;
        }
        int maxLevel = 4;
        try {
            List<com.zksy.base.alarm.domain.AlarmData> alarms = alarmDataMapper.selectList(
                    new LambdaQueryWrapper<com.zksy.base.alarm.domain.AlarmData>()
                            .eq(com.zksy.base.alarm.domain.AlarmData::getDeviceCode, deviceCode)
                            .eq(com.zksy.base.alarm.domain.AlarmData::getAlarmStatus, 0)
                            .orderByDesc(com.zksy.base.alarm.domain.AlarmData::getAlarmLevel)
                            .last("LIMIT 1")
            );
            if (CollUtil.isNotEmpty(alarms) && alarms.get(0).getAlarmLevel() != null) {
                maxLevel = alarms.get(0).getAlarmLevel();
            }
        } catch (Exception e) {
            log.warn("计算告警等级异常：{}", e.getMessage());
        }
        return maxLevel;
    }

    private void fillGpsFields(Object vo, BigDecimal longitude, BigDecimal latitude) {
        if (vo == null) return;
        try {
            java.lang.reflect.Field bdLon = vo.getClass().getDeclaredField("bdLon");
            java.lang.reflect.Field bdLat = vo.getClass().getDeclaredField("bdLat");
            bdLon.setAccessible(true);
            bdLat.setAccessible(true);
            bdLon.set(vo, longitude);
            bdLat.set(vo, latitude);
        } catch (Exception e) {
            log.debug("填充GPS字段异常：{}", e.getMessage());
        }
    }
}
