package com.ruoyi.ems.service.impl;

import com.huashe.common.utils.DateUtils;
import com.ruoyi.ems.domain.Area;
import com.ruoyi.ems.domain.EmsFacs;
import com.ruoyi.ems.domain.WaterMeterH;
import com.ruoyi.ems.mapper.WaterConsumptionMapper;
import com.ruoyi.ems.model.QueryMeter;
import com.ruoyi.ems.model.WaterConsumptionExportVO;
import com.ruoyi.ems.model.WaterConsumptionVO;
import com.ruoyi.ems.service.IAreaService;
import com.ruoyi.ems.service.IEmsFacsService;
import com.ruoyi.ems.service.IMeterBoundaryRelService;
import com.ruoyi.ems.service.IWaterConsumptionService;
import com.ruoyi.ems.util.AreaUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 用水统计服务实现
 */
@Service
public class WaterConsumptionServiceImpl implements IWaterConsumptionService {
    private static final Logger logger = LoggerFactory.getLogger(WaterConsumptionServiceImpl.class);

    @Autowired
    private WaterConsumptionMapper waterConsumptionMapper;

    @Autowired
    private IMeterBoundaryRelService meterBoundaryRelService;

    @Autowired
    private IEmsFacsService facsService;

    @Autowired
    private IAreaService areaService;

    /**
     * 水表计量类型常量
     */
    private static final int WATER_METER_CLS = 70;

    @Override
    public List<WaterMeterH> selectMDevWaterConsumptionList(QueryMeter queryMeter) {
        return waterConsumptionMapper.selectMDevWaterConsumptionList(queryMeter);
    }

    @Override
    public List<WaterConsumptionVO> selectAreaWaterConsumptionList(QueryMeter queryMeter) {
        if (queryMeter == null) {
            return Collections.emptyList();
        }

        // 1. 获取所有相关测点设备
        Set<String> meterDevices = getMeterDevicesByArea(queryMeter);
        if (meterDevices.isEmpty()) {
            return Collections.emptyList();
        }

        // 2. 根据时间维度调用相应的查询方法
        List<WaterConsumptionVO> result;
        switch (queryMeter.getTimeDimension().toLowerCase()) {
            case "day":
                result = waterConsumptionMapper.selectAreaDailyWaterConsumptionByDevices(queryMeter, meterDevices);
                break;
            case "month":
                result = waterConsumptionMapper.selectAreaMonthlyWaterConsumptionByDevices(queryMeter, meterDevices);
                break;
            case "year":
                result = waterConsumptionMapper.selectAreaYearlyWaterConsumptionByDevices(queryMeter, meterDevices);
                break;
            default:
                result = waterConsumptionMapper.selectAreaMonthlyWaterConsumptionByDevices(queryMeter, meterDevices);
        }

        // 填充区域名称路径
        fillAreaNameForElecConsumption(result);

        return result;
    }

    @Override
    public WaterConsumptionVO selectAreaWaterConsumptionSummary(QueryMeter queryMeter) {
        if (queryMeter == null) {
            return new WaterConsumptionVO();
        }

        // 1. 获取所有相关测点设备
        Set<String> meterDevices = getMeterDevicesByArea(queryMeter);
        if (meterDevices.isEmpty()) {
            return new WaterConsumptionVO();
        }

        // 2. 查询汇总数据
        WaterConsumptionVO summary = waterConsumptionMapper.selectAreaWaterConsumptionSummaryByDevices(queryMeter,
            meterDevices);
        return summary != null ? summary : new WaterConsumptionVO();
    }

    /**
     * 根据区域获取所有相关的水表设备（修复版本 - 参照用电实现）
     */
    private Set<String> getMeterDevicesByArea(QueryMeter queryMeter) {
        Set<String> meterDevices = new HashSet<>();

        try {
            // 确定查询的区域范围
            Set<String> targetAreaCodes = new HashSet<>();

            if (StringUtils.isNotBlank(queryMeter.getObjCode()) && !"-1".equals(queryMeter.getObjCode())) {
                // 指定了区域代码，需要查询该区域及其所有子区域（树节点点击传入的是objCode）
                targetAreaCodes.addAll(getAllChildAreaCodes(queryMeter.getObjCode()));
                logger.debug("根据objCode查询区域设备，区域代码: {}, 找到子区域数量: {}", queryMeter.getObjCode(),
                    targetAreaCodes.size());
            }

            // 如果没有指定任何区域，查询所有区域的所有水表
            if (targetAreaCodes.isEmpty()) {
                logger.debug("未指定区域，查询所有水表设备");

                // 关键修复：清除分页参数，避免影响测点设备查询
                com.github.pagehelper.PageHelper.clearPage();

                // 修复：objType应该是1（区域），不是2（设施）
                List<String> allDevices = meterBoundaryRelService.selectMeterDevices(null, 1, WATER_METER_CLS);
                if (!CollectionUtils.isEmpty(allDevices)) {
                    meterDevices.addAll(allDevices);
                    logger.debug("查询到所有区域水表设备数量: {}", allDevices.size());
                }
                else {
                    // 方法2：如果上面的方法没有数据，尝试获取所有区域，然后查询每个区域的设备
                    List<Area> allAreas = areaService.selectArea(new Area());
                    if (!CollectionUtils.isEmpty(allAreas)) {
                        for (Area area : allAreas) {
                            // 每次查询前清除分页参数
                            com.github.pagehelper.PageHelper.clearPage();

                            List<String> areaDevices = meterBoundaryRelService.selectMeterDevices(area.getAreaCode(), 1,
                                WATER_METER_CLS);
                            if (!CollectionUtils.isEmpty(areaDevices)) {
                                meterDevices.addAll(areaDevices);
                                logger.debug("区域 {} 找到水表设备数量: {}", area.getAreaCode(), areaDevices.size());
                            }
                        }
                    }
                }
            }
            else {
                // 根据区域代码获取绑定的测点设备
                for (String areaCode : targetAreaCodes) {
                    // 每次查询前清除分页参数
                    com.github.pagehelper.PageHelper.clearPage();

                    // 修复：objType应该是1（区域），不是2（设施）
                    List<String> devices = meterBoundaryRelService.selectMeterDevices(areaCode, 1, WATER_METER_CLS);
                    if (!CollectionUtils.isEmpty(devices)) {
                        meterDevices.addAll(devices);
                        logger.debug("区域 {} 找到水表设备数量: {}", areaCode, devices.size());
                    }
                }
            }

            logger.info("最终获取到的水表设备总数: {}", meterDevices.size());
            if (logger.isDebugEnabled()) {
                logger.debug("设备列表: {}", meterDevices);
            }

        }
        catch (Exception e) {
            logger.error("获取区域水表设备异常", e);
        }
        finally {
            // 确保分页参数被清理
            com.github.pagehelper.PageHelper.clearPage();
        }

        return meterDevices;
    }

    /**
     * 获取指定区域及其所有子区域的代码
     */
    private Set<String> getAllChildAreaCodes(String areaCode) {
        Set<String> areaCodes = new HashSet<>();

        // 1. 添加当前区域本身
        Area currentArea = areaService.selectAreaByCode(areaCode);
        if (currentArea != null) {
            areaCodes.add(currentArea.getAreaCode());
        }

        // 2. 获取当前区域的子区域树（递归获取）
        List<Area> childAreas = areaService.selectAreaTree(areaCode, true);

        // 3. 递归遍历子区域树，收集所有区域代码
        collectAreaCodes(childAreas, areaCodes);

        return areaCodes;
    }

    /**
     * 递归收集区域树中的所有区域代码
     */
    private void collectAreaCodes(List<?> areas, Set<String> areaCodes) {
        if (areas == null || areas.isEmpty()) {
            return;
        }

        for (Object obj : areas) {
            Area area = (Area) obj;
            areaCodes.add(area.getAreaCode());

            // 递归处理子区域
            if (area.getChildren() != null && !area.getChildren().isEmpty()) {
                collectAreaCodes(area.getChildren(), areaCodes);
            }
        }
    }

    @Override
    public List<WaterConsumptionVO> selectFacsWaterConsumptionList(QueryMeter queryMeter) {
        if (queryMeter == null) {
            return Collections.emptyList();
        }

        switch (queryMeter.getTimeDimension().toLowerCase()) {
            case "day":
                return waterConsumptionMapper.selectFacsDailyWaterConsumption(queryMeter);
            case "month":
                return waterConsumptionMapper.selectFacsMonthlyWaterConsumption(queryMeter);
            case "year":
                return waterConsumptionMapper.selectFacsYearlyWaterConsumption(queryMeter);
            default:
                return waterConsumptionMapper.selectFacsMonthlyWaterConsumption(queryMeter);
        }
    }

    @Override
    public WaterConsumptionVO selectMDevWaterConsumptionSummary(QueryMeter queryMeter) {
        return waterConsumptionMapper.selectMDevWaterConsumptionSummary(queryMeter);
    }

    @Override
    public WaterConsumptionVO selectFacsWaterConsumptionSummary(QueryMeter queryMeter) {
        if (queryMeter == null) {
            return new WaterConsumptionVO();
        }

        WaterConsumptionVO summary = waterConsumptionMapper.selectFacsWaterConsumptionSummary(queryMeter);
        return summary != null ? summary : new WaterConsumptionVO();
    }

    @Override
    public List<WaterConsumptionVO> exportAreaWaterConsumptionList(QueryMeter queryMeter) {
        if (queryMeter == null) {
            return Collections.emptyList();
        }

        // 导出时不分页
        queryMeter.setPageNum(null);
        queryMeter.setPageSize(null);

        return selectAreaWaterConsumptionList(queryMeter);
    }

    @Override
    public List<WaterConsumptionVO> exportFacsWaterConsumptionList(QueryMeter queryMeter) {
        if (queryMeter == null) {
            return Collections.emptyList();
        }

        // 导出时不分页
        queryMeter.setPageNum(null);
        queryMeter.setPageSize(null);

        return selectFacsWaterConsumptionList(queryMeter);
    }

    @Override
    public List<WaterMeterH> getAreaWaterHourMeter(QueryMeter queryMeter) {
        if (queryMeter == null) {
            logger.warn("查询参数为空，返回空列表");
            return Collections.emptyList();
        }

        try {
            // 设置默认排序
            if (StringUtils.isBlank(queryMeter.getOrderFlag())) {
                queryMeter.setOrderFlag("desc");
            }

            // 处理对象名称
            enrichAreaQueryMeter(queryMeter);

            // 获取区域绑定的所有水表设备
            Set<String> meterDevices = getAreaMeterDevicesForHourly(queryMeter);

            if (CollectionUtils.isEmpty(meterDevices)) {
                logger.info("未找到区域绑定的水表设备，区域: {}", queryMeter.getAreaCode());
                return Collections.emptyList();
            }

            logger.info("查询区域小时用水明细，区域: {}, 对象: {}, 设备数量: {}",
                queryMeter.getAreaCode(), queryMeter.getObjCode(), meterDevices.size());

            // 通过Mapper查询
            List<WaterMeterH> result = waterConsumptionMapper.selectAreaHourlyWaterConsumptionByDevices(
                queryMeter, meterDevices);

            return result != null ? result : Collections.emptyList();
        } catch (Exception e) {
            logger.error("查询区域小时用水明细异常", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<WaterMeterH> getFacsWaterHourMeter(QueryMeter queryMeter) {
        if (queryMeter == null) {
            logger.warn("查询参数为空，返回空列表");
            return Collections.emptyList();
        }

        try {
            // 设置默认计量类型
            if (queryMeter.getMeterCls() == null) {
                queryMeter.setMeterCls(WATER_METER_CLS);
            }

            // 设置默认排序
            if (StringUtils.isBlank(queryMeter.getOrderFlag())) {
                queryMeter.setOrderFlag("desc");
            }

            // 处理对象名称（用于结果展示）
            enrichFacsQueryMeter(queryMeter);

            logger.info("查询设施小时用水明细，区域: {}, 设施: {}, 设施分类: {}",
                queryMeter.getAreaCode(), queryMeter.getObjCode(), queryMeter.getFacsCategory());

            // 直接通过Mapper查询
            List<WaterMeterH> result = waterConsumptionMapper.selectFacsHourlyWaterConsumption(queryMeter);

            return result != null ? result : Collections.emptyList();
        } catch (Exception e) {
            logger.error("查询设施小时用水明细异常", e);
            return Collections.emptyList();
        }
    }

    @Override
    public List<WaterConsumptionVO> getFacsWaterHourSta(QueryMeter queryMeter) {
        if (queryMeter == null) {
            logger.warn("查询参数为空，返回空列表");
            return Collections.emptyList();
        }

        try {
            // 设置默认计量类型为水表
            if (queryMeter.getMeterCls() == null) {
                queryMeter.setMeterCls(WATER_METER_CLS);
            }

            logger.info("查询设施小时用水汇总，区域: {}, 设施分类: {}, 子类: {}",
                queryMeter.getAreaCode(), queryMeter.getFacsCategory(), queryMeter.getFacsSubCategory());

            // 直接通过Mapper一次查询完成
            List<WaterConsumptionVO> result = waterConsumptionMapper.selectFacsHourlyWaterSummary(queryMeter);

            return result != null ? result : Collections.emptyList();
        } catch (Exception e) {
            logger.error("查询设施小时用水汇总异常", e);
            return Collections.emptyList();
        }
    }

    /**
     * 为设施查询条件补充名称信息
     */
    private void enrichFacsQueryMeter(QueryMeter queryMeter) {
        String objCode = queryMeter.getObjCode();
        String areaCode = queryMeter.getAreaCode();

        if (StringUtils.isNotBlank(objCode) && !StringUtils.equals(objCode, areaCode)
            && !StringUtils.equals("-1", objCode)) {
            // 查询指定设施
            EmsFacs emsFacs = facsService.selectEmsFacsByCode(objCode);
            if (emsFacs != null) {
                queryMeter.setObjName(emsFacs.getFacsName());
            }
        } else if (StringUtils.equals("-1", areaCode)) {
            // 全部设施
            queryMeter.setObjCode("-1");
            queryMeter.setObjName("全部设施");
        } else if (StringUtils.isNotBlank(areaCode)) {
            // 指定区域下的设施
            Area area = areaService.selectAreaByCode(areaCode);
            if (area != null) {
                queryMeter.setObjCode(areaCode);
                queryMeter.setObjName(area.getAreaName());
            }
        }
    }

    /**
     * 为区域查询条件补充名称信息
     */
    private void enrichAreaQueryMeter(QueryMeter queryMeter) {
        String areaCode = queryMeter.getAreaCode();

        if (StringUtils.equals("-1", areaCode)) {
            queryMeter.setObjCode("-1");
            queryMeter.setObjName("全部区域");
        } else if (StringUtils.isNotBlank(queryMeter.getObjCode())) {
            Area area = areaService.selectAreaByCode(queryMeter.getObjCode());
            if (area != null) {
                queryMeter.setObjName(area.getAreaName());
            }
        }
    }

    /**
     * 获取区域绑定的水表设备（用于小时粒度查询）
     */
    private Set<String> getAreaMeterDevicesForHourly(QueryMeter queryMeter) {
        Set<String> meterDevices = new HashSet<>();
        String areaCode = queryMeter.getAreaCode();

        try {
            // 清除分页参数
            com.github.pagehelper.PageHelper.clearPage();

            if (StringUtils.equals("-1", areaCode)) {
                // 全部区域：获取所有区域的水表设备
                List<String> allDevices = meterBoundaryRelService.selectMeterDevices(null, 1, WATER_METER_CLS);
                if (CollectionUtils.isNotEmpty(allDevices)) {
                    meterDevices.addAll(allDevices);
                } else {
                    // 备选方案：遍历所有区域获取设备
                    List<Area> allAreas = areaService.selectArea(new Area());
                    if (CollectionUtils.isNotEmpty(allAreas)) {
                        for (Area area : allAreas) {
                            com.github.pagehelper.PageHelper.clearPage();
                            List<String> areaDevices = meterBoundaryRelService.selectMeterDevices(
                                area.getAreaCode(), 1, WATER_METER_CLS);
                            if (CollectionUtils.isNotEmpty(areaDevices)) {
                                meterDevices.addAll(areaDevices);
                            }
                        }
                    }
                }
            } else {
                // 指定区域：使用objCode或areaCode
                String targetCode = StringUtils.isNotBlank(queryMeter.getObjCode())
                    ? queryMeter.getObjCode() : areaCode;

                List<String> devices = meterBoundaryRelService.selectMeterDevices(targetCode, 1, WATER_METER_CLS);
                if (CollectionUtils.isNotEmpty(devices)) {
                    meterDevices.addAll(devices);
                }
            }
        } catch (Exception e) {
            logger.error("获取区域水表设备异常，区域: {}", areaCode, e);
        } finally {
            com.github.pagehelper.PageHelper.clearPage();
        }

        return meterDevices;
    }

    /**
     * 转换为用水导出VO列表
     */
    public List<WaterConsumptionExportVO> convertToWaterExportVOList(List<WaterConsumptionVO> originalList,
        String timeDimension) {
        if (originalList == null || originalList.isEmpty()) {
            return Collections.emptyList();
        }

        return originalList.stream().map(vo -> convertToWaterExportVO(vo, timeDimension))
            .collect(java.util.stream.Collectors.toList());
    }

    /**
     * 转换单个用水VO为导出VO
     */
    private WaterConsumptionExportVO convertToWaterExportVO(WaterConsumptionVO vo, String timeDimension) {
        WaterConsumptionExportVO exportVO = new WaterConsumptionExportVO();

        // 对象名称
        exportVO.setObjName(vo.getObjName());

        // 统计时间 - 根据时间维度格式化
        exportVO.setStatisticTime(formatStatisticTime(vo, timeDimension));

        // 用水量和费用 - 格式化为2位小数
        exportVO.setTotalWaterQuantity(formatNumber(vo.getTotalWaterQuantity(), 2));
        exportVO.setTotalWaterCost(formatNumber(vo.getTotalWaterCost(), 2));

        return exportVO;
    }

    /**
     * 格式化统计时间
     */
    private String formatStatisticTime(WaterConsumptionVO vo, String timeDimension) {
        if (timeDimension == null) {
            timeDimension = "month";
        }

        switch (timeDimension.toLowerCase()) {
            case "day":
                return formatDateForDisplay(vo.getStatisticDate());
            case "month":
                return StringUtils.isNotBlank(vo.getStatisticMonth()) ? vo.getStatisticMonth() : "";
            case "year":
                return vo.getStatisticYear() != null ? vo.getStatisticYear().toString() : "";
            default:
                return StringUtils.isNotBlank(vo.getStatisticMonth()) ? vo.getStatisticMonth() : "";
        }
    }

    /**
     * 数字格式化
     */
    private String formatNumber(java.math.BigDecimal num, int decimals) {
        if (num == null) {
            StringBuilder sb = new StringBuilder("0.");
            for (int i = 0; i < decimals; i++) {
                sb.append("0");
            }
            return sb.toString();
        }
        return String.format("%." + decimals + "f", num.doubleValue());
    }

    /**
     * 日期格式化用于显示
     */
    private String formatDateForDisplay(Date dateObj) {
        return DateUtils.dateToString(dateObj, "yyyy-MM-dd");
    }

    /**
     * 填充区域用电统计的区域名称路径
     */
    private void fillAreaNameForElecConsumption(List<WaterConsumptionVO> consumptionList) {
        if (org.springframework.util.CollectionUtils.isEmpty(consumptionList)) {
            return;
        }

        try {
            // 获取所有区域信息
            List<Area> areas = areaService.selectArea(new Area());
            Map<String, Area> areaMap = areas.stream()
                .collect(Collectors.toMap(Area::getAreaCode, Function.identity()));

            // 为每个统计记录填充区域路径名称
            for (WaterConsumptionVO vo : consumptionList) {
                fillAreaNameForSingleRecord(vo, areaMap);
            }

            logger.debug("完成用电统计区域名称填充，记录数: {}", consumptionList.size());
        }
        catch (Exception e) {
            logger.error("填充用电统计区域名称异常", e);
        }
    }

    /**
     * 为单条记录填充区域名称
     */
    private void fillAreaNameForSingleRecord(WaterConsumptionVO vo, Map<String, Area> areaMap) {
        if (vo == null || StringUtils.isBlank(vo.getObjCode())) {
            return;
        }

        // 获取区域完整路径名称
        String areaNamePath = AreaUtils.getAreaNamePath(vo.getObjCode(), areaMap);

        // 如果原名称是简单的名称（如"二楼"），用路径名称替换
        if (StringUtils.isNotBlank(areaNamePath)) {
            vo.setObjName(areaNamePath);
            logger.debug("区域名称已替换: {} -> {}", vo.getObjCode(), areaNamePath);
        }
    }
}