/*
 * 文 件 名:  BoundaryObjServiceImpl
 * 版    权:  华设设计集团股份有限公司
 * 描    述:  <描述>
 * 修 改 人:  lvwenbin
 * 修改时间:  2025/1/13
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.ruoyi.ems.service.impl;

import com.huashe.common.exception.Assert;
import com.huashe.common.exception.BusinessException;
import com.ruoyi.ems.core.BaseCache;
import com.ruoyi.ems.domain.Area;
import com.ruoyi.ems.domain.EnergyMeter;
import com.ruoyi.ems.domain.ElecMeterH;
import com.ruoyi.ems.domain.FacsCategory;
import com.ruoyi.ems.domain.FacsSubCategory;
import com.ruoyi.ems.domain.MeterBoundaryRel;
import com.ruoyi.ems.enums.MeterObjType;
import com.ruoyi.ems.model.BoundaryObj;
import com.ruoyi.ems.model.QueryMeter;
import com.ruoyi.ems.service.IAreaService;
import com.ruoyi.ems.service.IBoundaryObjService;
import com.ruoyi.ems.service.IElecMeterHService;
import com.ruoyi.ems.service.IEmsFacsService;
import com.ruoyi.ems.service.IMeterBoundaryRelService;
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.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * <一句话功能简述>
 * <功能详细描述>
 *
 * @author lvwenbin
 * @version [版本号, 2025/1/13]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service
public class BoundaryObjServiceImpl implements IBoundaryObjService {
    private static final Logger log = LoggerFactory.getLogger(BoundaryObjServiceImpl.class);

    @Qualifier("emsCommonCache")
    @Autowired
    private BaseCache emsCommonCache;

    // 注入区域服务
    @Autowired
    private IAreaService areaService;

    // 注入设施服务
    @Autowired
    private IEmsFacsService emsFacsService;

    // 注入电表数据服务
    @Autowired
    private IElecMeterHService elecMeterHService;

    // 注入边界对象关系服务
    @Autowired
    private IMeterBoundaryRelService boundaryRelService;

    /**
     * 根据区域编码、对象类型和对象代码获取边界对象
     *
     * @param areaCode 区域编码
     * @return 边界对象
     */
    @Override
    public BoundaryObj getBoundaryByArea(String areaCode) {
        BoundaryObj boundaryObj = null;

        try {
            // 查询电表绑定关系
            List<MeterBoundaryRel> relList = boundaryRelService.selectRelByObj(null, MeterObjType.METER_AREA.getType(),
                45);
            Map<String, Set<MeterBoundaryRel>> relMap = relList.stream()
                .collect(Collectors.groupingBy(MeterBoundaryRel::getBoundaryObj, Collectors.toSet()));

            // 根据区域编码获取根节点
            Area rootArea = areaService.selectAreaByCode(areaCode);
            Assert.notNull(rootArea, -1, "区域不存在");
            // 下级区域递归
            List<Area> subList = areaService.selectAreaTree(areaCode, true);

            // 递归转换
            boundaryObj = recursionConvert(rootArea, subList, relMap);
        }
        catch (BusinessException e) {
            log.debug(e.getMessage());
        }

        return boundaryObj;
    }

    /**
     * 查询设施用电统计
     *
     * @param queryMeter 查询条件对象，用于指定查询条件
     * @return 返回电表信息列表，如果未找到符合条件的数据，则返回空列表
     */
    @Override
    public List<EnergyMeter> getMeterStaByFacsCategory(QueryMeter queryMeter) {
        List<EnergyMeter> result = new ArrayList<>();
        List<BoundaryObj> bObjs = emsFacsService.getFacsWithMeterDev(queryMeter.getAreaCode(),
            queryMeter.getFacsCategory(), queryMeter.getFacsSubCategory());

        if (CollectionUtils.isNotEmpty(bObjs)) {
            for (BoundaryObj bObj : bObjs) {
                EnergyMeter meter = new EnergyMeter();
                meter.setAreaCode(queryMeter.getAreaCode());
                meter.setObjType(bObj.getObjType());
                meter.setObjCode(bObj.getObjCode());
                meter.setObjName(bObj.getObjName());

                if (CollectionUtils.isNotEmpty(bObj.getBindElecMeterDevs())) {
                    EnergyMeter staObj = getElecMeter(queryMeter, bObj);

                    if (null != staObj) {
                        meter.setQuantity(staObj.getQuantity());
                        meter.setUseCost(staObj.getUseCost());
                    }
                }

                result.add(meter);
            }
        }

        return result;
    }

    @Override
    public List<ElecMeterH> getMeterByFacsCategory(QueryMeter queryMeter) {
        List<ElecMeterH> result = new ArrayList<>();
        List<BoundaryObj> bObjs = emsFacsService.getFacsWithMeterDev(queryMeter.getAreaCode(),
            queryMeter.getFacsCategory(), queryMeter.getFacsSubCategory());

        if (CollectionUtils.isNotEmpty(bObjs)) {
            Set<String> devCodes = new HashSet<>();

            for (BoundaryObj bObj : bObjs) {
                if (CollectionUtils.isNotEmpty(bObj.getBindElecMeterDevs())) {
                    devCodes.addAll(bObj.getBindElecMeterDevs());
                }
            }

            String objCode = null;
            String objName = null;

            if (StringUtils.isNotEmpty(queryMeter.getFacsSubCategory())) {
                objCode = queryMeter.getFacsSubCategory();
                FacsSubCategory facsSubCategory = emsCommonCache.getSubCategory(objCode);
                objName = null != facsSubCategory ? facsSubCategory.getName() : "未知";
            }
            else {
                objCode = queryMeter.getFacsCategory();
                FacsCategory facsCategory = emsCommonCache.getCategory(objCode);
                objName = null != facsCategory ? facsCategory.getName() : "未知";
            }

            QueryMeter condition = new QueryMeter();
            condition.setAreaCode(queryMeter.getAreaCode());
            condition.setObjType(MeterObjType.METER_FACS.getType());
            condition.setObjCode(objCode);
            condition.setObjName(objName);
            condition.setStartRecTime(queryMeter.getStartRecTime());
            condition.setEndRecTime(queryMeter.getEndRecTime());
            condition.setDeviceCodes(devCodes);

            result = elecMeterHService.selectByMeterDevs(condition);
        }

        return result;
    }

    @Override
    public List<EnergyMeter> getMeterStaByBoundaryObj(QueryMeter queryMeter) {
        return Collections.emptyList();
    }

    @Override
    public List<ElecMeterH> getMeterByBoundaryObj(QueryMeter queryMeter) {
        return Collections.emptyList();
    }

    private EnergyMeter getElecMeter(QueryMeter queryMeter, BoundaryObj bObj) {
        QueryMeter condition = new QueryMeter();
        condition.setAreaCode(queryMeter.getAreaCode());
        condition.setObjType(MeterObjType.METER_FACS.getType());
        condition.setObjCode(bObj.getObjCode());
        condition.setObjName(bObj.getObjName());
        condition.setStartRecTime(queryMeter.getStartRecTime());
        condition.setEndRecTime(queryMeter.getEndRecTime());
        condition.setDeviceCodes(bObj.getBindElecMeterDevs());

        EnergyMeter meterRes = elecMeterHService.staByMeterDev(condition);
        return meterRes;
    }

    /**
     * 递归构造边界-绑定电表 的树结构
     *
     * @param parentArea 根区域
     * @param subList    子区列表
     * @param relMap     关联电表集合
     * @return 边界树结构对象
     */
    private BoundaryObj recursionConvert(Area parentArea, List<?> subList, Map<String, Set<MeterBoundaryRel>> relMap) {
        BoundaryObj boundaryObj = new BoundaryObj();
        boundaryObj.setObjType(MeterObjType.METER_AREA.getType());
        boundaryObj.setObjCode(parentArea.getAreaCode());
        boundaryObj.setObjName(parentArea.getAreaName());

        // 设置直接绑定的电表
        Set<MeterBoundaryRel> relSet = relMap.get(parentArea.getAreaCode());

        if (CollectionUtils.isNotEmpty(relSet)) {
            Set<String> bindDevs = relSet.stream().map(MeterBoundaryRel::getMeterDevice).collect(Collectors.toSet());
            boundaryObj.setBindElecMeterDevs(bindDevs);
        }

        List<BoundaryObj> subObjs = new ArrayList<>();
        boundaryObj.setChildren(subObjs);

        if (CollectionUtils.isNotEmpty(subList)) {
            // 递归封装子区边界对象
            for (Object obj : subList) {
                Area area = (Area) obj;
                BoundaryObj sonObj = recursionConvert(area, area.getChildren(), relMap);
                subObjs.add(sonObj);
            }

            // 设置子区绑定电表
            boundaryObj.setSubElecMeterDevs(getSubElecMeterDev(subList, relMap));
        }

        return boundaryObj;
    }

    /**
     * 获取子区绑定的电表
     *
     * @param subList 子区对象
     * @param relMap  关联电表集合
     * @return 子区绑定电表集合
     */
    private Set<String> getSubElecMeterDev(List<?> subList, Map<String, Set<MeterBoundaryRel>> relMap) {
        Set<String> subRelSet = new HashSet<>();

        for (Object obj : subList) {
            Area area = (Area) obj;

            Set<MeterBoundaryRel> tempSubrelSet = relMap.get(area.getAreaCode());

            // 场景1：直接绑定在子区对象的电表
            if (CollectionUtils.isNotEmpty(tempSubrelSet)) {
                Set<String> bindDevs = tempSubrelSet.stream().map(MeterBoundaryRel::getMeterDevice)
                    .collect(Collectors.toSet());
                subRelSet.addAll(bindDevs);
            }
            // 场景2：绑定在子区下属区域的电表
            else {
                List<?> subSubList = area.getChildren();

                if (CollectionUtils.isNotEmpty(subSubList)) {
                    subRelSet.addAll(getSubElecMeterDev(subSubList, relMap));
                }
            }
        }

        return subRelSet;
    }
}