package com.ruoyi.ems.service.impl;

import com.huashe.common.utils.DateUtils;
import com.ruoyi.ems.domain.Area;
import com.ruoyi.ems.domain.EmsDevice;
import com.ruoyi.ems.domain.EmsFacs;
import com.ruoyi.ems.mapper.AdmEmsIndexRangeMapper;
import com.ruoyi.ems.mapper.EmsFacsMapper;
import com.ruoyi.ems.model.BoundaryObj;
import com.ruoyi.ems.model.QueryDevice;
import com.ruoyi.ems.model.TreeEntity;
import com.ruoyi.ems.service.IAreaService;
import com.ruoyi.ems.service.IEmsDeviceService;
import com.ruoyi.ems.service.IEmsFacsService;
import com.ruoyi.ems.util.AreaUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 能源设施/系统Service业务层处理
 *
 * @author ruoyi
 * @date 2024-07-10
 */
@Service
public class EmsFacsServiceImpl implements IEmsFacsService {
    @Autowired
    private EmsFacsMapper emsFacsMapper;

    @Autowired
    private IEmsDeviceService deviceService;

    @Autowired
    private IAreaService areaService;

    @Autowired
    private AdmEmsIndexRangeMapper admEmsIndexRangeMapper;

    /**
     * 查询能源设施
     *
     * @param id 能源设施主键
     * @return 能源设施
     */
    @Override
    public EmsFacs selectEmsFacsById(Long id) {
        return emsFacsMapper.selectEmsFacsById(id);
    }

    @Override
    public EmsFacs selectEmsFacsByCode(String code) {
        // 查询设施对象
        return emsFacsMapper.selectEmsFacsByCode(code);
    }

    /**
     * 查询能源设施列表
     *
     * @param emsFacs 能源设施
     * @return 能源设施
     */
    @Override
    public List<EmsFacs> selectEmsFacsList(EmsFacs emsFacs) {
        return emsFacsMapper.selectEmsFacsList(emsFacs);
    }

    /**
     * 根据设施获取设备树结构
     *
     * @param queryDevice 查询条件
     * @return 设备树结构
     */
    @Override
    public List<TreeEntity> getFacsDevTree(QueryDevice queryDevice) {
        List<TreeEntity> retList = new ArrayList<>();

        if (StringUtils.isEmpty(queryDevice.getAreaCode())) {
            List<Area> areaTree = areaService.selectAreaTree("0", true);
            List<Area> areaList = AreaUtils.compressTree(areaTree);
            Map<String, Area> areaMap = areaList.stream()
                .collect(Collectors.toMap(Area::getAreaCode, Function.identity()));

            if (CollectionUtils.isNotEmpty(areaTree)) {
                EmsFacs facsParam = new EmsFacs();
                facsParam.setFacsCategory(queryDevice.getDeviceCategory());
                List<EmsFacs> facsList = selectEmsFacsList(facsParam);

                for (Area area : areaTree) {
                    QueryDevice param = new QueryDevice();
                    BeanUtils.copyProperties(queryDevice, param);
                    param.setAreaCode(area.getAreaCode());

                    List<EmsDevice> devices = deviceService.selectList(param);
                    Map<String, List<EmsDevice>> deviceMap = devices.stream()
                        .collect(Collectors.groupingBy(EmsDevice::getRefFacs));

                    TreeEntity entity = new TreeEntity();
                    entity.setId(area.getAreaCode());
                    entity.setLabel(area.getAreaName());
                    entity.setChildren(buildFacsDevSub(facsList, deviceMap, areaMap));
                    retList.add(entity);
                }
            }
        }
        else {
            Area area = areaService.selectAreaByCode(queryDevice.getAreaCode());
            List<Area> areaTree = areaService.selectAreaTree(queryDevice.getAreaCode(), true);
            List<Area> areaList = AreaUtils.compressTree(areaTree);
            Map<String, Area> areaMap = areaList.stream()
                .collect(Collectors.toMap(Area::getAreaCode, Function.identity()));

            if (null != area) {
                EmsFacs facsParam = new EmsFacs();
                facsParam.setRefArea(area.getAreaCode());
                facsParam.setFacsCategory(queryDevice.getDeviceCategory());
                List<EmsFacs> facsList = selectEmsFacsList(facsParam);

                QueryDevice param = new QueryDevice();
                BeanUtils.copyProperties(queryDevice, param);
                param.setAreaCode(queryDevice.getAreaCode());

                List<EmsDevice> devices = deviceService.selectList(param);
                Map<String, List<EmsDevice>> deviceMap = devices.stream()
                    .collect(Collectors.groupingBy(EmsDevice::getRefFacs));

                TreeEntity entity = new TreeEntity();
                entity.setId(area.getAreaCode());
                entity.setLabel(area.getAreaName());
                entity.setChildren(buildFacsDevSub(facsList, deviceMap, areaMap));

                retList.add(entity);
            }
        }

        return retList;
    }

    @Override
    public List<BoundaryObj> getFacsWithMeterDev(String areaCode, String category, String subCategory,
        Integer meterCls) {
        List<BoundaryObj> facsMeterObjs = emsFacsMapper.selectFacsWithMeter(areaCode, category, subCategory, meterCls);

        if (CollectionUtils.isNotEmpty(facsMeterObjs)) {
            for (BoundaryObj obj : facsMeterObjs) {
                String[] array = StringUtils.split(obj.getBindMeterDevsStr(), ",");
                List<String> devList = ArrayUtils.isNotEmpty(array) ? Arrays.asList(array) : new ArrayList<>();

                Set<String> bindDevs = devList.stream().map(String::trim).filter(s -> !s.isEmpty())
                    .collect(Collectors.toSet());
                obj.setBindMeterDevs(bindDevs);
            }
        }
        return facsMeterObjs;
    }

    private List<TreeEntity> buildFacsDevSub(List<EmsFacs> facsList, Map<String, List<EmsDevice>> deviceMap,
        Map<String, Area> areaMap) {
        List<TreeEntity> retList = new ArrayList<>();

        for (EmsFacs facs : facsList) {
            boolean hasSub = false;
            List<TreeEntity> subList = null;
            List<EmsDevice> devices = deviceMap.get(facs.getFacsCode());

            if (CollectionUtils.isNotEmpty(devices)) {
                subList = new ArrayList<>();

                for (EmsDevice device : devices) {
                    hasSub = true;
                    String namePrefix = AreaUtils.getAreaNamePath(device.getLocationRef(), areaMap);

                    String label = StringUtils.isNotBlank(namePrefix) ?
                        namePrefix + " - " + device.getDeviceName() :
                        device.getDeviceName();

                    TreeEntity entity = new TreeEntity();
                    entity.setId(device.getDeviceCode());
                    entity.setLabel(label);
                    subList.add(entity);
                }
            }

            TreeEntity entity = new TreeEntity();
            entity.setId(facs.getFacsCode());
            entity.setLabel(facs.getFacsName());
            entity.setChildren(subList);

            if (hasSub) {
                retList.add(entity);
            }
        }

        return retList;
    }

    /**
     * 新增能源设施/系统
     *
     * @param emsFacs 能源设施/系统
     * @return 结果
     */
    @Override
    public int insertEmsFacs(EmsFacs emsFacs) {
        emsFacs.setCreateTime(DateUtils.getNowDate());
        return emsFacsMapper.insertEmsFacs(emsFacs);
    }

    /**
     * 修改能源设施/系统
     *
     * @param emsFacs 能源设施/系统
     * @return 结果
     */
    @Override
    public int updateEmsFacs(EmsFacs emsFacs) {
        emsFacs.setUpdateTime(DateUtils.getNowDate());
        return emsFacsMapper.updateEmsFacs(emsFacs);
    }

    /**
     * 批量删除能源设施
     *
     * @param ids 需要删除的能源设施主键
     * @return 结果
     */
    @Override
    public int deleteEmsFacsByIds(Long[] ids) {
        return emsFacsMapper.deleteEmsFacsByIds(ids);
    }

    /**
     * 删除能源设施/系统信息
     *
     * @param id 能源设施/系统主键
     * @return 结果
     */
    @Override
    public int deleteEmsFacsById(Long id) {
        return emsFacsMapper.deleteEmsFacsById(id);
    }
}
