import { PropertiesService } from "../properties";
import { PropertyAggregate } from "../properties/dtos";
import * as T from "./dtos";

function average(values: Array<number | null | undefined>): { avg: number | null; count: number } {
  const nums = values.filter((value): value is number => value !== null && value !== undefined);
  if (nums.length === 0) return { avg: null, count: 0 };

  const sum = nums.reduce((acc, value) => acc + value, 0);
  return { avg: sum / nums.length, count: nums.length };
}

function formatAvg(avg: number | null): string | null {
  return avg === null ? null : avg.toFixed(2);
}

function matchesFilters(aggregate: PropertyAggregate, filters: T.StatisticsFormRequest): boolean {
  const { property } = aggregate;

  if (filters.state && property.state !== filters.state) return false;

  if (filters.country) {
    const country = property.country ?? "";
    if (!country.toLowerCase().includes(filters.country.toLowerCase())) return false;
  }

  const createdAt = new Date(property.createdAt);

  if (filters.startDate && createdAt < new Date(filters.startDate)) return false;

  if (filters.endDate) {
    const endOfDay = new Date(`${filters.endDate}T23:59:59.999`);
    if (createdAt > endOfDay) return false;
  }

  return true;
}

function buildLicenseDetails(
  aggregates: PropertyAggregate[],
  field: "hasEnvironmentalLicense" | "hasWaterGrant",
): T.LicensesDetails {
  const total = aggregates.length;
  const counts = { SIM: 0, NAO: 0, DISPENSA: 0 };

  for (const aggregate of aggregates) {
    const value = aggregate.property[field];
    if (value === "SIM" || value === "NAO" || value === "DISPENSA") {
      counts[value]++;
    }
  }

  const toIndicator = (count: number): T.LicensesIndicator => ({
    count,
    percentage: total > 0 ? (count / total) * 100 : 0,
  });

  return {
    sim: toIndicator(counts.SIM),
    nao: toIndicator(counts.NAO),
    dispensa: toIndicator(counts.DISPENSA),
  };
}

export const StatisticsService = {
  async getStatistics(filters: T.StatisticsFormRequest): Promise<T.DataFormResponse> {
    const allAggregates = await PropertiesService.getAllAggregated();
    const aggregates = allAggregates.filter((aggregate) => matchesFilters(aggregate, filters));

    const milk = average(aggregates.map((a) => a.property.milkLitersPerDayProperty));
    const cows = average(aggregates.map((a) => a.property.lactatingCows));
    const idh = average(aggregates.map((a) => a.waterPerformanceIndex?.finalScore));

    const production: T.ProductionResponse = {
      avgMilkLitersPerDayProperty: formatAvg(milk.avg),
      avgLactatingCows: formatAvg(cows.avg),
      avgIDH: formatAvg(idh.avg),
      totalProperties: aggregates.length,
    };

    const licenses: T.LicensesResponse = {
      environmentalLicense: buildLicenseDetails(aggregates, "hasEnvironmentalLicense"),
      waterGrant: buildLicenseDetails(aggregates, "hasWaterGrant"),
    };

    const waterManagementMacro = average(aggregates.map((a) => a.waterPerformanceIndex?.waterManagementScore));
    const waterQualityConservationMacro = average(
      aggregates.map((a) => a.waterPerformanceIndex?.waterQualityConservationScore),
    );
    const wasteManagementMacro = average(aggregates.map((a) => a.waterPerformanceIndex?.wasteManagementScore));
    const waterPerformanceIndexMacro = average(aggregates.map((a) => a.waterPerformanceIndex?.finalScore));

    const macroIndicators: T.MacroIndicatorsResponse = {
      waterManagement: { avg: formatAvg(waterManagementMacro.avg), indicatorCount: waterManagementMacro.count },
      waterQualityConservation: {
        avg: formatAvg(waterQualityConservationMacro.avg),
        indicatorCount: waterQualityConservationMacro.count,
      },
      wasteManagement: { avg: formatAvg(wasteManagementMacro.avg), indicatorCount: wasteManagementMacro.count },
      waterPerformanceIndex: {
        avg: formatAvg(waterPerformanceIndexMacro.avg),
        indicatorCount: waterPerformanceIndexMacro.count,
      },
    };

    const consumoAgua = average(aggregates.map((a) => a.meso.consumoAgua));
    const perdasAgua = average(aggregates.map((a) => a.meso.perdasAgua));
    const segurancaHidrica = average(aggregates.map((a) => a.meso.segurancaHidrica));
    const qualidadeAgua = average(aggregates.map((a) => a.meso.qualidadeAgua));
    const conservacaoAgua = average(aggregates.map((a) => a.meso.conservacaoAgua));
    const estrutura = average(aggregates.map((a) => a.meso.estrutura));
    const manejoResiduo = average(aggregates.map((a) => a.meso.manejoResiduo));
    const adubacao = average(aggregates.map((a) => a.meso.adubacao));

    const mesoIndicators: T.MesoIndicatorsResponse = {
      waterManagement: {
        consumoAgua: formatAvg(consumoAgua.avg),
        perdasAgua: formatAvg(perdasAgua.avg),
        segurancaHidrica: formatAvg(segurancaHidrica.avg),
      },
      waterQualityConservation: {
        qualidadeAgua: formatAvg(qualidadeAgua.avg),
        conservacaoAgua: formatAvg(conservacaoAgua.avg),
      },
      wasteManagement: {
        estrutura: formatAvg(estrutura.avg),
        manejoResiduo: formatAvg(manejoResiduo.avg),
        adubacao: formatAvg(adubacao.avg),
      },
    };

    return { filters, production, licenses, macroIndicators, mesoIndicators };
  },
};
