/**
 * Algoritmo principal para la predicción de crecimiento de Varroa
 */

import { ParametrosModelo, ResultadoPrediccion, ResultadoDiario, Tratamiento } from './types';
import { CONSTANTES_VARROA } from './constants';
import { calcularProduccionHuevos } from './brood-model';
import { calcularPoblacionAbejas } from './bee-population';
import { calcularFactorRalentizacion, calcularProbabilidadExposicion } from './growth-factors';

/**
 * Genera una predicción de crecimiento de Varroa basada en una muestra inicial
 * @param params - Parámetros del modelo
 * @returns Resultados de la predicción
 */
export function generarPrediccionVarroa(params: ParametrosModelo): ResultadoPrediccion {
  // Valores por defecto
  const parametros: Required<ParametrosModelo> = {
    numAcaros: params.numAcaros,
    numAbejas: params.numAbejas,
    fechaMuestra: params.fechaMuestra,
    tratamientos: params.tratamientos || [],
    inicioTemporadaCria: params.inicioTemporadaCria || CONSTANTES_VARROA.DIA_INICIO_CRIA,
    finTemporadaCria: params.finTemporadaCria || CONSTANTES_VARROA.DIA_FIN_CRIA,
    pausaCria: params.pausaCria || null,
    tasaCrecimiento: params.tasaCrecimiento || CONSTANTES_VARROA.TASA_CRECIMIENTO_ESTANDAR,
    tasaMortalidad: params.tasaMortalidad || CONSTANTES_VARROA.TASA_MORTALIDAD_ESTANDAR,
    diasPrediccion: params.diasPrediccion || CONSTANTES_VARROA.DIAS_PREDICCION_DEFECTO
  };
  
  // Calcular día del año de fecha muestra
  const fechaInicio = new Date(params.fechaMuestra);
  const inicioAnio = new Date(fechaInicio.getFullYear(), 0, 1);
  const diaDelAnio = Math.floor(
    (fechaInicio.getTime() - inicioAnio.getTime()) / 
    (24 * 60 * 60 * 1000)
  ) + 1;
  
  // Iniciar cálculos
  const resultados = calcularPrediccion(
    parametros, 
    diaDelAnio
  );
  
  return resultados;
}

/**
 * Función que realiza los cálculos día a día
 * @param params - Parámetros del modelo
 * @param diaInicio - Día del año en que comienza la predicción
 * @returns Resultados de la predicción
 */
function calcularPrediccion(
  params: Required<ParametrosModelo>,
  diaInicio: number
): ResultadoPrediccion {
  const resultadosDiarios: ResultadoDiario[] = [];
  const inicioAnio = new Date(params.fechaMuestra.getFullYear(), 0, 1);
  
  // Estimar población inicial de abejas
  const poblacionAbejas = calcularPoblacionAbejas(diaInicio);
  
  // Estimar población inicial de ácaros
  let N = (params.numAcaros / params.numAbejas) * poblacionAbejas;
  
  // Preparar mapa de tratamientos por día
  const mapaTratamientos = new Map<number, Tratamiento>();
  for (const tratamiento of params.tratamientos) {
    const tratDia = Math.floor(
      (tratamiento.fecha.getTime() - inicioAnio.getTime()) / 
      (24 * 60 * 60 * 1000)
    ) + 1;
    mapaTratamientos.set(tratDia, tratamiento);
  }
  
  // Iterar días de predicción
  for (let dia = diaInicio; dia < diaInicio + params.diasPrediccion; dia++) {
    // Ajustar día para años siguientes
    const diaAjustado = dia > 365 ? dia - 365 : dia;
    
    // Calcular fecha actual
    const fechaActual = new Date(inicioAnio);
    fechaActual.setDate(inicioAnio.getDate() + dia - 1);
    
    // Calcular producción de huevos (Bt)
    const produccionHuevos = calcularProduccionHuevos(
      diaAjustado, 
      params.inicioTemporadaCria, 
      params.finTemporadaCria,
      params.pausaCria
    );
    
    // Calcular producción de huevos 7 días atrás (Bt-7)
    const diaAtrasoAjustado = diaAjustado - 7 > 0 ? diaAjustado - 7 : diaAjustado - 7 + 365;
    const produccionHuevosAtrasada = calcularProduccionHuevos(
      diaAtrasoAjustado, 
      params.inicioTemporadaCria, 
      params.finTemporadaCria,
      params.pausaCria
    );
    
    // Calcular factores de crecimiento
    const X = calcularFactorRalentizacion(N, produccionHuevosAtrasada);
    const Y = calcularProbabilidadExposicion(N, produccionHuevosAtrasada);
    
    // Comprobar tratamientos
    if (mapaTratamientos.has(diaAjustado)) {
      const tratamiento = mapaTratamientos.get(diaAjustado)!;
      N = N * ((100 - tratamiento.eficiencia) / 100);
    } else {
      // Aplicar tasa de crecimiento
      // Aumento en otoño (después del día 225, aproximadamente 13 de agosto)
      const Rg = diaAjustado <= 225 ? params.tasaCrecimiento : params.tasaCrecimiento * 1.2;
      
      // Calcular nuevo N
      N = N * Math.exp(Rg * X) * Math.exp(params.tasaMortalidad * (1 + Y));
    }
    
    // Calcular caída natural
    const caidaNatural = N * Math.abs(params.tasaMortalidad) * (1 + Y);
    
    // Calcular infestación en abejas adultas
    const poblacionAbejasActual = calcularPoblacionAbejas(diaAjustado);
    const infestacionAbejas = (N * Y * 100) / poblacionAbejasActual;
    
    // Guardar resultados
    resultadosDiarios.push({
      dia: diaAjustado,
      fecha: new Date(fechaActual),
      poblacionAcaros: N,
      caidaNatural,
      infestacionAbejas,
      umbralExcedido: infestacionAbejas > CONSTANTES_VARROA.UMBRAL_INFESTACION_CRITICO
    });
  }
  
  // Calcular estadísticas
  const maximaInfo = resultadosDiarios.reduce(
    (max, actual) => actual.poblacionAcaros > max.poblacion 
      ? { poblacion: actual.poblacionAcaros, fecha: actual.fecha } 
      : max,
    { poblacion: 0, fecha: new Date() }
  );
  
  const promedioInfestacion = resultadosDiarios.reduce(
    (sum, item) => sum + item.infestacionAbejas, 0
  ) / resultadosDiarios.length;
  
  return {
    parametrosEntrada: params,
    resultadosDiarios,
    estadisticas: {
      maximaPoblacion: maximaInfo.poblacion,
      fechaMaxima: maximaInfo.fecha,
      promedioInfestacion
    }
  };
}
