package com.usky.ems.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.usky.common.mybatis.core.AbstractCrudService;
import com.usky.common.security.utils.SecurityUtils;
import com.usky.ems.domain.EmsDeviceItemCode;
import com.usky.ems.domain.EmsEnergyConsumptionFormula;
import com.usky.ems.domain.EmsEnergyItemCode;
import com.usky.ems.domain.EmsProductEnergyType;
import com.usky.ems.mapper.EmsDeviceItemCodeMapper;
import com.usky.ems.mapper.EmsEnergyConsumptionFormulaMapper;
import com.usky.ems.mapper.EmsEnergyItemCodeMapper;
import com.usky.ems.mapper.EmsProductEnergyTypeMapper;
import com.usky.ems.service.EmsEnergyItemCodeService;
import com.usky.ems.service.vo.EnergyItemCodeVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

/**
 * 能源分项编码 服务实现类
 */
@Service
public class EmsEnergyItemCodeServiceImpl
        extends AbstractCrudService<EmsEnergyItemCodeMapper, EmsEnergyItemCode>
        implements EmsEnergyItemCodeService {

    @Autowired
    private EmsEnergyConsumptionFormulaMapper energyConsumptionFormulaMapper;
    @Autowired
    private EmsProductEnergyTypeMapper emsProductEnergyTypeMapper;
    @Autowired
    private EmsDeviceItemCodeMapper emsDeviceItemCodeMapper;

    @Override
    public List<EnergyItemCodeVO> querySpaceEnergyItem(Long spaceId) {
        if (spaceId == null) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<EmsEnergyConsumptionFormula> lambdaQuery =
                Wrappers.lambdaQuery(EmsEnergyConsumptionFormula.class)
                        .eq(EmsEnergyConsumptionFormula::getSpaceId, spaceId);
        List<EmsEnergyConsumptionFormula> formulaList = energyConsumptionFormulaMapper.selectList(lambdaQuery);
        if (formulaList == null || formulaList.isEmpty()) {
            return Collections.emptyList();
        }

        List<String> codes = formulaList.stream()
                .map(EmsEnergyConsumptionFormula::getItemCode)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());

        if (codes.isEmpty()) {
            return Collections.emptyList();
        }

        // 直接从 ems_energy_item_code 表根据编码列表查询
        List<EmsEnergyItemCode> itemCodeList = this.list(
                Wrappers.<EmsEnergyItemCode>lambdaQuery()
                        .in(EmsEnergyItemCode::getCode, codes)
        );
        if (itemCodeList == null || itemCodeList.isEmpty()) {
            return Collections.emptyList();
        }

        // PO -> VO
        List<EnergyItemCodeVO> itemCodes = itemCodeList.stream().map(po -> {
            EnergyItemCodeVO vo = new EnergyItemCodeVO();
            vo.setCode(po.getCode());
            vo.setParentCode(po.getParentCode());
            vo.setName(po.getName());
            vo.setUnit(po.getUnit());
            vo.setUnitName(po.getUnitName());
            return vo;
        }).collect(Collectors.toList());

        // 仅保留配置了公式的分项
        itemCodes = itemCodes.stream()
                .filter(vo -> codes.contains(vo.getCode()))
                .collect(Collectors.toList());

        if (itemCodes.isEmpty()) {
            return Collections.emptyList();
        }

        Map<String, List<EnergyItemCodeVO>> listMap = itemCodes.stream()
                .collect(Collectors.groupingBy(EnergyItemCodeVO::getParentCode));

        Map<String, EmsEnergyConsumptionFormula> formulaMap = formulaList.stream()
                .collect(Collectors.toMap(EmsEnergyConsumptionFormula::getItemCode, f -> f, (a, b) -> a));

        List<EnergyItemCodeVO> result = new ArrayList<>(itemCodes);

        for (EnergyItemCodeVO codeVO : itemCodes) {
            List<EnergyItemCodeVO> children = listMap.get(codeVO.getCode());
            if (children != null && !children.isEmpty()) {
                codeVO.setChildren(children);
                result.removeAll(children);
            }

            EmsEnergyConsumptionFormula formula = formulaMap.get(codeVO.getCode());
            if (formula != null) {
                codeVO.setId(formula.getId());
                codeVO.setFormula(formula.getFormula());
                if (formula.getName() != null) {
                    codeVO.setName(formula.getName());
                }
            }
        }

        return result;
    }

    @Override
    public List<EmsEnergyItemCode> listEnergyTypes(Integer energyType) {
        List<EmsEnergyItemCode> energyTypes = listRootEnergyTypes(energyType);
        if (energyTypes.isEmpty()) {
            return energyTypes;
        }
        Map<Integer, List<Long>> productIdsByEnergyType = loadProductIdsByEnergyType(SecurityUtils.getTenantId());
        for (EmsEnergyItemCode energyType1 : energyTypes) {
            energyType1.setProductIdList(
                    productIdsByEnergyType.getOrDefault(energyType1.getEnergyType(), Collections.emptyList()));
        }
        return energyTypes;
    }

    @Override
    public List<EmsEnergyItemCode> listEnergySubItems() {
        List<String> rootCodes = listRootEnergyTypes(null).stream()
                .map(EmsEnergyItemCode::getCode)
                .filter(Objects::nonNull)
                .distinct()
                .collect(Collectors.toList());
        if (rootCodes.isEmpty()) {
            return Collections.emptyList();
        }
        List<EmsEnergyItemCode> energySubItems = this.list(
                Wrappers.<EmsEnergyItemCode>lambdaQuery()
                        .in(EmsEnergyItemCode::getParentCode, rootCodes)
                        .orderByAsc(EmsEnergyItemCode::getParentCode, EmsEnergyItemCode::getCode));
        if (energySubItems.isEmpty()) {
            return energySubItems;
        }
        Map<String, List<String>> deviceUuidsByItemCode = loadDeviceUuidsByItemCode(SecurityUtils.getTenantId());
        for (EmsEnergyItemCode energySubItem : energySubItems) {
            energySubItem.setDeviceUuidList(
                    deviceUuidsByItemCode.getOrDefault(energySubItem.getCode(), Collections.emptyList()));
        }
        return energySubItems;
    }

    private List<EmsEnergyItemCode> listRootEnergyTypes(Integer energyType) {
        LambdaQueryWrapper<EmsEnergyItemCode> wrapper = Wrappers.<EmsEnergyItemCode>lambdaQuery()
                .eq(EmsEnergyItemCode::getParentCode, "0")
                .eq(energyType != null, EmsEnergyItemCode::getEnergyType, energyType)
                .orderByAsc(EmsEnergyItemCode::getCode);
        return this.list(wrapper);
    }

    private Map<Integer, List<Long>> loadProductIdsByEnergyType(Integer tenantId) {
        List<EmsProductEnergyType> bindings = emsProductEnergyTypeMapper.selectList(
                Wrappers.<EmsProductEnergyType>lambdaQuery()
                        .eq(EmsProductEnergyType::getTenantId, tenantId));
        if (bindings.isEmpty()) {
            return Collections.emptyMap();
        }
        return bindings.stream()
                .filter(binding -> binding.getEnergyType() != null && binding.getProductId() != null)
                .collect(Collectors.groupingBy(
                        EmsProductEnergyType::getEnergyType,
                        Collectors.mapping(EmsProductEnergyType::getProductId, Collectors.toList())));
    }

    private Map<String, List<String>> loadDeviceUuidsByItemCode(Integer tenantId) {
        List<EmsDeviceItemCode> bindings = emsDeviceItemCodeMapper.selectList(
                Wrappers.<EmsDeviceItemCode>lambdaQuery()
                        .eq(EmsDeviceItemCode::getTenantId, tenantId));
        if (bindings.isEmpty()) {
            return Collections.emptyMap();
        }
        return bindings.stream()
                .filter(binding -> binding.getItemCode() != null && binding.getDeviceUuid() != null)
                .collect(Collectors.groupingBy(
                        EmsDeviceItemCode::getItemCode,
                        Collectors.mapping(EmsDeviceItemCode::getDeviceUuid, Collectors.toList())));
    }
}

