import { CrudService } from "../crud";
import {
  PropertyEntity,
  WasteManagementEntity,
  WaterManagementEntity,
  WaterPerformanceIndexEntity,
  WaterQualityConservationEntity,
} from "../entities/dtos";
import * as T from "./dtos";
import {
  computeAdubacao,
  computeConservacaoAgua,
  computeConsumoAgua,
  computeEstrutura,
  computeManejoResiduo,
  computePerdasAgua,
  computeQualidadeAgua,
  computeSegurancaHidrica,
} from "../statistics/utils/meso";

function indexByPropertyId<TRecord extends { propertyId: number }>(
  records: TRecord[],
): Map<number, TRecord> {
  const map = new Map<number, TRecord>();
  for (const record of records) {
    map.set(record.propertyId, record);
  }
  return map;
}

export const PropertiesService = {
  async getAllAggregated(): Promise<T.PropertyAggregate[]> {
    const [properties, waterPerformanceIndexes, waterManagements, waterQualityConservations, wasteManagements] =
      await Promise.all([
        CrudService.retrieveAllPages<PropertyEntity>("Properties"),
        CrudService.retrieveAllPages<WaterPerformanceIndexEntity>("WaterPerformanceIndex"),
        CrudService.retrieveAllPages<WaterManagementEntity>("WaterManagement"),
        CrudService.retrieveAllPages<WaterQualityConservationEntity>("WaterQualityConservation"),
        CrudService.retrieveAllPages<WasteManagementEntity>("WasteManagement"),
      ]);

    const waterPerformanceIndexByPropertyId = indexByPropertyId(waterPerformanceIndexes);
    const waterManagementByPropertyId = indexByPropertyId(waterManagements);
    const waterQualityConservationByPropertyId = indexByPropertyId(waterQualityConservations);
    const wasteManagementByPropertyId = indexByPropertyId(wasteManagements);

    return properties.map((property) => {
      const waterManagement = waterManagementByPropertyId.get(property.id) ?? null;
      const waterQualityConservation = waterQualityConservationByPropertyId.get(property.id) ?? null;
      const wasteManagement = wasteManagementByPropertyId.get(property.id) ?? null;

      return {
        property,
        waterPerformanceIndex: waterPerformanceIndexByPropertyId.get(property.id) ?? null,
        waterManagement,
        waterQualityConservation,
        wasteManagement,
        meso: {
          consumoAgua: waterManagement ? computeConsumoAgua(waterManagement) : null,
          perdasAgua: waterManagement ? computePerdasAgua(waterManagement) : null,
          segurancaHidrica: waterManagement ? computeSegurancaHidrica(waterManagement) : null,
          qualidadeAgua: waterQualityConservation ? computeQualidadeAgua(waterQualityConservation) : null,
          conservacaoAgua: waterQualityConservation ? computeConservacaoAgua(waterQualityConservation) : null,
          estrutura: wasteManagement ? computeEstrutura(wasteManagement) : null,
          manejoResiduo: wasteManagement ? computeManejoResiduo(wasteManagement) : null,
          adubacao: wasteManagement ? computeAdubacao(wasteManagement) : null,
        },
      };
    });
  },
};
