// Algoritmos para calcular formatos de torneo según N de equipos.
// Implementación literal de los que pegó el usuario.

export interface FormatoTorneo {
  cantidadGrupos: number;
  equiposPorGrupo: number;
  clasificadosFijosPorGrupo: number;
  totalClasificadosFijos: number;
  cuposMejoresPosicionados: number;
  descripcion: string;
}

export interface RepartoJusto {
  gruposGrandes: { cantidad: number; tamaño: number; pasesDirectos: number };
  gruposPequeños: { cantidad: number; tamaño: number; pasesDirectos: number };
  totalPasesDirectos: number;
  comodines: number;
}

export type FormatosResult = {
  n_equipos: number;
  es_primo: boolean;
  fallback_aplicado: boolean;
  opciones_compuesto: FormatoTorneo[];
  reparto_primo: RepartoJusto | null;
};

function esPrimo(n: number): boolean {
  if (n < 2) return false;
  if (n === 2) return true;
  if (n % 2 === 0) return false;
  for (let i = 3; i * i <= n; i += 2) if (n % i === 0) return false;
  return true;
}

function generarConfiguracion(
  cantidadGrupos: number,
  equiposPorGrupo: number
): FormatoTorneo {
  const clasificadosFijosPorGrupo = Math.floor(16 / cantidadGrupos);
  const cuposMejoresPosicionados = 16 % cantidadGrupos;
  return {
    cantidadGrupos,
    equiposPorGrupo,
    clasificadosFijosPorGrupo,
    totalClasificadosFijos: clasificadosFijosPorGrupo * cantidadGrupos,
    cuposMejoresPosicionados,
    descripcion: `Formato de ${cantidadGrupos} grupos. Avanzan los ${clasificadosFijosPorGrupo} mejores de cada grupo. Los ${cuposMejoresPosicionados} cupos restantes se asignan a los mejores siguientes puestos en la tabla general.`,
  };
}

function calcularFormatosDisponibles(totalEquipos: number): FormatoTorneo[] {
  const formatos: FormatoTorneo[] = [];
  for (let i = 2; i <= Math.sqrt(totalEquipos); i++) {
    if (totalEquipos % i === 0) {
      const gruposA = i;
      const equiposA = totalEquipos / i;
      formatos.push(generarConfiguracion(gruposA, equiposA));
      if (gruposA !== equiposA) {
        formatos.push(generarConfiguracion(equiposA, gruposA));
      }
    }
  }
  return formatos.sort((a, b) => a.cantidadGrupos - b.cantidadGrupos);
}

function calcularClasificacionAsimetrica(
  totalEquipos: number,
  numGrupos = 8
): RepartoJusto {
  const metaClasificados = 16;
  const ratioClasificacion = metaClasificados / totalEquipos;

  const tamañoPequeño = Math.floor(totalEquipos / numGrupos);
  const tamañoGrande = tamañoPequeño + 1;

  const cantGruposGrandes = totalEquipos % numGrupos;
  const cantGruposPequeños = numGrupos - cantGruposGrandes;

  const pasesGrupoGrande = Math.floor(tamañoGrande * ratioClasificacion);
  const pasesGrupoPequeño = Math.floor(tamañoPequeño * ratioClasificacion);

  const totalDirectosGrandes = cantGruposGrandes * pasesGrupoGrande;
  const totalDirectosPequeños = cantGruposPequeños * pasesGrupoPequeño;
  const totalPasesDirectos = totalDirectosGrandes + totalDirectosPequeños;

  const comodines = metaClasificados - totalPasesDirectos;

  return {
    gruposGrandes: {
      cantidad: cantGruposGrandes,
      tamaño: tamañoGrande,
      pasesDirectos: pasesGrupoGrande,
    },
    gruposPequeños: {
      cantidad: cantGruposPequeños,
      tamaño: tamañoPequeño,
      pasesDirectos: pasesGrupoPequeño,
    },
    totalPasesDirectos,
    comodines,
  };
}

/** Si comodines > 4 → fallback a "8 grupos x 2 mejores" forzado. */
function aplicarFallbackPrimo(totalEquipos: number): RepartoJusto {
  const tamañoPequeño = Math.floor(totalEquipos / 8);
  const tamañoGrande = tamañoPequeño + 1;
  const cantGruposGrandes = totalEquipos % 8;
  const cantGruposPequeños = 8 - cantGruposGrandes;
  return {
    gruposGrandes: {
      cantidad: cantGruposGrandes,
      tamaño: tamañoGrande,
      pasesDirectos: 2,
    },
    gruposPequeños: {
      cantidad: cantGruposPequeños,
      tamaño: tamañoPequeño,
      pasesDirectos: 2,
    },
    totalPasesDirectos: 16,
    comodines: 0,
  };
}

export function calcularFormatos(totalEquipos: number): FormatosResult {
  if (totalEquipos < 4) {
    return {
      n_equipos: totalEquipos,
      es_primo: false,
      fallback_aplicado: false,
      opciones_compuesto: [],
      reparto_primo: null,
    };
  }

  const primo = esPrimo(totalEquipos);

  if (!primo) {
    return {
      n_equipos: totalEquipos,
      es_primo: false,
      fallback_aplicado: false,
      opciones_compuesto: calcularFormatosDisponibles(totalEquipos),
      reparto_primo: null,
    };
  }

  const reparto = calcularClasificacionAsimetrica(totalEquipos);
  if (reparto.comodines > 4) {
    return {
      n_equipos: totalEquipos,
      es_primo: true,
      fallback_aplicado: true,
      opciones_compuesto: [],
      reparto_primo: aplicarFallbackPrimo(totalEquipos),
    };
  }
  return {
    n_equipos: totalEquipos,
    es_primo: true,
    fallback_aplicado: false,
    opciones_compuesto: [],
    reparto_primo: reparto,
  };
}
