import {
  WasteManagementEntity,
  WaterManagementEntity,
  WaterQualityConservationEntity,
} from "../../entities/dtos";

function isClose(value: number, target: number, eps = 0.01): boolean {
  return Math.abs(value - target) < eps;
}

/** Sums value*weight for whichever entries are non-null, without redistributing the omitted weight. */
function weightedSumOmitNulls(entries: Array<[number | null | undefined, number]>): number | null {
  let sum = 0;
  let hasAny = false;

  for (const [value, weight] of entries) {
    if (value === null || value === undefined) continue;
    sum += value * weight;
    hasAny = true;
  }

  return hasAny ? sum : null;
}

export function computeConsumoAgua(wm: WaterManagementEntity): number | null {
  return weightedSumOmitNulls([
    [wm.hasHydraulicMapScore, 0.173],
    [wm.hasWaterMeasurementScore, 0.205],
    [wm.measurementFrequencyScore, 0.191],
    [wm.monitoredConsumptionScore, 0.186],
    [wm.hasReductionGoalsScore, 0.245],
  ]);
}

const PERDAS_AGUA_BASE_WEIGHTS: Record<string, number> = {
  hasFlowControlSystemScore: 0.149,
  hasLevelFloatDrinkersScore: 0.156,
  hasLevelFloatStorageScore: 0.145,
  leakIdentificationScore: 0.222,
  irrigationProgramScore: 0.179,
  coolingSystemScore: 0.149,
};

export function computePerdasAgua(wm: WaterManagementEntity): number | null {
  const values: Record<string, number | null | undefined> = {
    hasFlowControlSystemScore: wm.hasFlowControlSystemScore,
    hasLevelFloatDrinkersScore: wm.hasLevelFloatDrinkersScore,
    hasLevelFloatStorageScore: wm.hasLevelFloatStorageScore,
    leakIdentificationScore: wm.leakIdentificationScore,
    irrigationProgramScore: wm.irrigationProgramScore,
    coolingSystemScore: wm.coolingSystemScore,
  };

  const presentKeys = Object.keys(PERDAS_AGUA_BASE_WEIGHTS).filter(
    (key) => values[key] !== null && values[key] !== undefined,
  );
  if (presentKeys.length === 0) return null;

  const weightSum = presentKeys.reduce((acc, key) => acc + PERDAS_AGUA_BASE_WEIGHTS[key], 0);

  return presentKeys.reduce((acc, key) => {
    const normalizedWeight = PERDAS_AGUA_BASE_WEIGHTS[key] / weightSum;
    return acc + (values[key] as number) * normalizedWeight;
  }, 0);
}

export function computeSegurancaHidrica(wm: WaterManagementEntity): number | null {
  return weightedSumOmitNulls([
    [wm.rainwaterHarvestScore, 0.505],
    [wm.waterReuseScore, 0.495],
  ]);
}

export function computeQualidadeAgua(wq: WaterQualityConservationEntity): number | null {
  return weightedSumOmitNulls([
    [wq.monitorsQualityScore, 0.263],
    [wq.monitoredWaterPointsPercentScore, 0.223],
    [wq.nitrateAnalysisScore, 0.254],
    [wq.ecoliAnalysisScore, 0.26],
  ]);
}

export function computeConservacaoAgua(wq: WaterQualityConservationEntity): number | null {
  return weightedSumOmitNulls([
    [wq.animalsAccessWaterBodiesScore, 0.216],
    [wq.drinkerWaterSupplyScore, 0.304],
    [wq.waterAccumulationAreasScore, 0.233],
    [wq.drinkerCleaningFrequencyScore, 0.247],
  ]);
}

function estruturaWeights(impermeabilizedSystemScore: number | null | undefined) {
  if (impermeabilizedSystemScore !== null && impermeabilizedSystemScore !== undefined) {
    if (isClose(impermeabilizedSystemScore, 1)) {
      return {
        wasteStorageSystemScore: 0.223,
        impermeabilizedSystemScore: 0.227,
        rainwaterDivertedScore: 0.15,
        systemLeaksScore: 0.238,
        roofGuttersScore: 0.162,
      };
    }
    if (isClose(impermeabilizedSystemScore, 0.67)) {
      return {
        wasteStorageSystemScore: 0.306,
        impermeabilizedSystemScore: 0,
        rainwaterDivertedScore: 0.206,
        systemLeaksScore: 0.326,
        roofGuttersScore: 0.162,
      };
    }
  }

  return {
    wasteStorageSystemScore: 0.838,
    impermeabilizedSystemScore: 0,
    rainwaterDivertedScore: 0,
    systemLeaksScore: 0,
    roofGuttersScore: 0.162,
  };
}

export function computeEstrutura(ws: WasteManagementEntity): number | null {
  const weights = estruturaWeights(ws.impermeabilizedSystemScore);

  return weightedSumOmitNulls([
    [ws.wasteStorageSystemScore, weights.wasteStorageSystemScore],
    [ws.impermeabilizedSystemScore, weights.impermeabilizedSystemScore],
    [ws.rainwaterDivertedScore, weights.rainwaterDivertedScore],
    [ws.systemLeaksScore, weights.systemLeaksScore],
    [ws.roofGuttersScore, weights.roofGuttersScore],
  ]);
}

export function computeManejoResiduo(ws: WasteManagementEntity): number | null {
  return weightedSumOmitNulls([
    [ws.floorWashingPercentageScore, 0.223],
    [ws.manureRakingScore, 0.294],
    [ws.pressureWashingScore, 0.282],
    [ws.emergencyPlanScore, 0.201],
  ]);
}

export function computeAdubacao(ws: WasteManagementEntity): number | null {
  return weightedSumOmitNulls([
    [ws.fertilizerDocumentationScore, 0.167],
    [ws.organicResidueLabScore, 0.21],
    [ws.soilAnalysisScore, 0.262],
    [ws.residueApplicationFrequencyScore, 0.174],
    [ws.residueApplicationMethodScore, 0.187],
  ]);
}
