package com.usky.ems.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.usky.ems.domain.EmsDevice;
import com.usky.ems.domain.EmsDeviceFunction;
import com.usky.ems.enums.TemporalTypeEnum;
import com.usky.ems.mapper.EmsDeviceFunctionMapper;
import com.usky.ems.mapper.EmsDeviceMapper;
import com.usky.ems.service.BaseSpaceService;
import com.usky.ems.service.EmsDeviceReportService;
import com.usky.ems.service.vo.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 设备能耗报表相关服务实现（全部逻辑在 Service 层，Mapper 仅用标准 CRUD）
 */
@Service
public class EmsDeviceReportServiceImpl implements EmsDeviceReportService {

    @Autowired
    private BaseSpaceService baseSpaceService;

    @Autowired
    private EmsDeviceMapper emsDeviceMapper;

    @Autowired
    private EmsDeviceFunctionMapper emsDeviceFunctionMapper;

    @Override
    public List<DeviceEnergyReportItemVO> showEnergyReportDevices(DeviceEnergyReportRequest dto) {
        if (dto == null || dto.getProjectId() == null) {
            return Collections.emptyList();
        }

        // 1. 授权空间
        List<Long> spaceIds = baseSpaceService.getAuthorizedSpaceIds(dto.getSpaceId());

        // 2. 在 Service 层用 LambdaQueryWrapper 查 ems_device
        LambdaQueryWrapper<EmsDevice> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(EmsDevice::getProjectId, dto.getProjectId());

        if (dto.getProductIdList() != null && !dto.getProductIdList().isEmpty()) {
            wrapper.in(EmsDevice::getProductId, dto.getProductIdList());
        }
        if (dto.getDeviceSystem() != null) {
            wrapper.eq(EmsDevice::getDeviceSystem, dto.getDeviceSystem());
        }
        if (spaceIds != null && !spaceIds.isEmpty()) {
            wrapper.and(w -> w.in(EmsDevice::getInstallationLocation, spaceIds)
                    .or().in(EmsDevice::getMonitoringLocation, spaceIds));
        }
        if (dto.getGatewayId() != null && !dto.getGatewayId().isEmpty()) {
            wrapper.eq(EmsDevice::getGatewayId, dto.getGatewayId());
        }
        if (dto.getChannelId() != null) {
            wrapper.eq(EmsDevice::getChannelId, dto.getChannelId());
        }

        List<EmsDevice> devices = emsDeviceMapper.selectList(wrapper);
        if (devices == null || devices.isEmpty()) {
            return Collections.emptyList();
        }

        // 3. 转为 List<DeviceEnergyReportItemVO>
        List<DeviceEnergyReportItemVO> deviceList = devices.stream()
                .map(this::deviceToVo)
                .collect(Collectors.toList());

        // 4. 按 identifier 过滤：只保留在 ems_device_function 中存在该 identifier 的设备
        if (dto.getIdentifier() != null && !dto.getIdentifier().isEmpty()) {
            List<String> deviceIds = deviceList.stream()
                    .map(DeviceEnergyReportItemVO::getId)
                    .filter(Objects::nonNull)
                    .filter(id -> !id.isEmpty())
                    .collect(Collectors.toList());

            if (!deviceIds.isEmpty()) {
                LambdaQueryWrapper<EmsDeviceFunction> funcWrapper = new LambdaQueryWrapper<>();
                funcWrapper.select(EmsDeviceFunction::getDeviceId)
                        .in(EmsDeviceFunction::getDeviceId, deviceIds)
                        .eq(EmsDeviceFunction::getIdentifier, dto.getIdentifier());
                List<EmsDeviceFunction> deviceFunctions = emsDeviceFunctionMapper.selectList(funcWrapper);
                if (deviceFunctions != null && !deviceFunctions.isEmpty()) {
                    Set<String> meetDeviceIds = deviceFunctions.stream()
                            .map(EmsDeviceFunction::getDeviceId)
                            .collect(Collectors.toSet());
                    deviceList = deviceList.stream()
                            .filter(vo -> meetDeviceIds.contains(vo.getId()))
                            .collect(Collectors.toList());
                }
            }
        }

        // 5. 按 name 排序（不区分大小写）
        if (!deviceList.isEmpty()) {
            deviceList.sort(Comparator.comparing(
                    DeviceEnergyReportItemVO::getName,
                    Comparator.nullsLast(String.CASE_INSENSITIVE_ORDER)
            ));
        }

        return deviceList;
    }

    @Override
    public Object showEnergyReportData(DeviceFunctionValueReportDTO dto) {
        checkParams(dto);
        TemporalTypeEnum temporalTypeEnum = TemporalTypeEnum.get(dto.getTimeType());
        LocalDateTime startLocalTime = dto.getStartTime();
        LocalDateTime endLocalTime = dto.getEndTime();
        String identifier = getDeviceFunctionIdentifierByEnergyType(dto.getEnergyType());
        if (temporalTypeEnum != null) {
            checkDateTime(startLocalTime, endLocalTime, temporalTypeEnum);
            startLocalTime = temporalTypeEnum.normalizeStart(startLocalTime);
            endLocalTime = temporalTypeEnum.normalizeEnd(endLocalTime);
            DeviceFunctionLastValueDTO paramDTO = convertParamDTO(dto, startLocalTime, endLocalTime, temporalTypeEnum, identifier);
            return asyncProcessData(dto, paramDTO, temporalTypeEnum);
        } else {
            DeviceFunctionOneValueDTO paramDTO = convertParamOneLastValueDTO(dto, startLocalTime, endLocalTime, identifier);
            return getCustomizeEnergyReportVOList(dto, paramDTO, startLocalTime);
        }
    }

    private void checkParams(DeviceFunctionValueReportDTO dto) {
        if (dto == null) {
            throw new IllegalArgumentException("请求参数不能为空");
        }
        if (dto.getProjectId() == null) {
            throw new IllegalArgumentException("projectId 不能为空");
        }
        if (dto.getStartTime() == null || dto.getEndTime() == null) {
            throw new IllegalArgumentException("开始时间和结束时间不能为空");
        }
    }

    private void checkDateTime(LocalDateTime start, LocalDateTime end, TemporalTypeEnum type) {
        if (start.isAfter(end)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }
        // 如需限制时间跨度，可在此扩展逻辑（例如：按日最多查询31天）。
    }

    private String getDeviceFunctionIdentifierByEnergyType(Integer energyType) {
        if (energyType == null) {
            return "total_kwh";
        }
        switch (energyType) {
            case 1:
                return "total_kwh";
            case 2:
                return "total_water";
            case 3:
                return "total_gas";
            default:
                return "total_kwh";
        }
    }

    private DeviceFunctionLastValueDTO convertParamDTO(DeviceFunctionValueReportDTO src,
                                                       LocalDateTime start,
                                                       LocalDateTime end,
                                                       TemporalTypeEnum temporalTypeEnum,
                                                       String identifier) {
        DeviceFunctionLastValueDTO dto = new DeviceFunctionLastValueDTO();
        dto.setProjectId(src.getProjectId());
        dto.setDeviceIds(src.getDeviceIds());
        dto.setAttributePointIds(src.getAttributePointIds());
        dto.setTimeType(temporalTypeEnum != null ? temporalTypeEnum.getCode() : null);
        dto.setStartTime(start);
        dto.setEndTime(end);
        dto.setIdentifier(identifier);
        return dto;
    }

    private DeviceFunctionOneValueDTO convertParamOneLastValueDTO(DeviceFunctionValueReportDTO src,
                                                                  LocalDateTime start,
                                                                  LocalDateTime end,
                                                                  String identifier) {
        DeviceFunctionOneValueDTO dto = new DeviceFunctionOneValueDTO();
        dto.setProjectId(src.getProjectId());
        dto.setDeviceIds(src.getDeviceIds());
        dto.setAttributePointIds(src.getAttributePointIds());
        dto.setStartTime(start);
        dto.setEndTime(end);
        dto.setIdentifier(identifier);
        return dto;
    }

    private Object asyncProcessData(DeviceFunctionValueReportDTO origin,
                                    DeviceFunctionLastValueDTO paramDTO,
                                    TemporalTypeEnum temporalTypeEnum) {
        Map<String, Object> result = new HashMap<>();
        result.put("timeType", temporalTypeEnum != null ? temporalTypeEnum.getCode() : null);
        result.put("startTime", paramDTO.getStartTime());
        result.put("endTime", paramDTO.getEndTime());

        // 模拟数据：根据 deviceIds 与 attributePointIds 生成简单的时间序列数据
        List<Map<String, Object>> items = new ArrayList<>();
        List<String> deviceIds = paramDTO.getDeviceIds() != null ? paramDTO.getDeviceIds() : Collections.emptyList();
        List<Long> attrIds = paramDTO.getAttributePointIds() != null ? paramDTO.getAttributePointIds() : Collections.emptyList();

        int index = 0;
        for (String deviceId : deviceIds) {
            for (Long attrId : attrIds) {
                Map<String, Object> item = new HashMap<>();
                item.put("deviceId", deviceId);
                item.put("attributePointId", attrId);
                item.put("identifier", paramDTO.getIdentifier());
                // 简单模拟一个数值：100 + 10 * index
                item.put("value", 100 + 10 * index);
                item.put("unit", "kWh");
                items.add(item);
                index++;
            }
        }

        result.put("items", items);
        return result;
    }

    private Object getCustomizeEnergyReportVOList(DeviceFunctionValueReportDTO origin,
                                                  DeviceFunctionOneValueDTO paramDTO,
                                                  LocalDateTime startLocalTime) {
        Map<String, Object> result = new HashMap<>();
        result.put("time", startLocalTime);

        List<Map<String, Object>> items = new ArrayList<>();
        List<String> deviceIds = paramDTO.getDeviceIds() != null ? paramDTO.getDeviceIds() : Collections.emptyList();
        List<Long> attrIds = paramDTO.getAttributePointIds() != null ? paramDTO.getAttributePointIds() : Collections.emptyList();

        int index = 0;
        for (String deviceId : deviceIds) {
            for (Long attrId : attrIds) {
                Map<String, Object> item = new HashMap<>();
                item.put("deviceId", deviceId);
                item.put("attributePointId", attrId);
                item.put("identifier", paramDTO.getIdentifier());
                // 单点场景模拟一个数值：200 + 5 * index
                item.put("value", 200 + 5 * index);
                item.put("unit", "kWh");
                items.add(item);
                index++;
            }
        }

        result.put("items", items);
        return result;
    }

    private DeviceEnergyReportItemVO deviceToVo(EmsDevice d) {
        DeviceEnergyReportItemVO vo = new DeviceEnergyReportItemVO();
        vo.setId(d.getId());
        vo.setName(d.getName());
        vo.setNumber(d.getNumber());
        vo.setProjectId(d.getProjectId());
        vo.setProductId(d.getProductId());
        vo.setInstallationLocation(d.getInstallationLocation());
        vo.setMonitoringLocation(d.getMonitoringLocation());
        vo.setChannelId(d.getChannelId());
        vo.setGatewayId(d.getGatewayId());
        vo.setDeviceSystem(d.getDeviceSystem());
        vo.setStatus(d.getStatus());
        vo.setLocation(d.getLocation());
        return vo;
    }
}

