Source: controllers/c_obtenerAlumnos.js

/**
 * @fileoverview Funciones para rellenar selects con alumnos y generar Excel de inscripciones.
 * @author Mauricio Peña
 */

import M_obtenerAlumnos from "/InscripcionesEVG/assets/js/models/m_obtenerAlumnos.js";
import { ModalConfirmacion } from "/InscripcionesEVG/assets/js/utils/modalConfirmacion.js";

/**
 * Rellena los selects masculinos y femeninos con alumnos de una clase dada,
 * asegurando que las opciones seleccionadas no se repitan entre selects.
 *
 * @param {string|number} idClase - Identificador de la clase para obtener alumnos.
 * @returns {Promise<void>}
 */
async function rellenarSelectsConAlumnos(idClase) {
	try {
		const modelo = new M_obtenerAlumnos();
		const alumnos = await modelo.obtenerAlumnos(idClase);

		const contenedorMasculino = document.getElementById(
			"camposPruebasMasculina",
		);
		const contenedorFemenino = document.getElementById("camposPruebasFemenina");

		if (!contenedorMasculino || !contenedorFemenino) {
			console.warn("Contenedores no encontrados.");
			return;
		}

		const selectsMasculinos = contenedorMasculino.querySelectorAll("select");
		const selectsFemeninos = contenedorFemenino.querySelectorAll("select");

		const seleccionadosGenerales = new Set(); // Para selects normales
		const seleccionadosTipoC = new Set(); // Para selects con name "C"
		const anteriores = new Map(); // Guardamos el valor anterior de cada select

		/**
		 * Actualiza la visibilidad de las opciones en los selects para evitar duplicados.
		 */
		function actualizarSelects() {
			[...selectsMasculinos, ...selectsFemeninos].forEach((select) => {
				const options = select.querySelectorAll("option");
				const esTipoC = select.name === "C";

				options.forEach((option) => {
					const alumnoId = option.value;
					if (!alumnoId) return;

					// Ocultar las opciones de alumnos ya seleccionados excepto la opción actual del select
					if (esTipoC) {
						option.style.display =
							seleccionadosTipoC.has(alumnoId) &&
							anteriores.get(select) !== alumnoId
								? "none"
								: "";
					} else {
						option.style.display =
							seleccionadosGenerales.has(alumnoId) &&
							anteriores.get(select) !== alumnoId
								? "none"
								: "";
					}
				});
			});
		}

		// Rellenar selects masculinos con alumnos de sexo masculino
		selectsMasculinos.forEach((select) => {
			const esTipoC = select.name === "C";
			select.innerHTML = `<option value="">Selecciona</option>`;
			alumnos
				.filter((a) => {
					if (a.sexo !== "M") return false;
					if (!esTipoC && seleccionadosGenerales.has(a.idAlumno.toString()))
						return false;
					return true;
				})
				.forEach((alumno) => {
					const option = document.createElement("option");
					option.value = alumno.idAlumno;
					option.textContent = alumno.nombre;
					select.appendChild(option);
				});
		});

		// Rellenar selects femeninos con alumnos de sexo femenino
		selectsFemeninos.forEach((select) => {
			const esTipoC = select.name === "C";
			select.innerHTML = `<option value="">Selecciona</option>`;
			alumnos
				.filter((a) => {
					if (a.sexo !== "F") return false;
					if (!esTipoC && seleccionadosGenerales.has(a.idAlumno.toString()))
						return false;
					return true;
				})
				.forEach((alumno) => {
					const option = document.createElement("option");
					option.value = alumno.idAlumno;
					option.textContent = alumno.nombre;
					select.appendChild(option);
				});
		});

		// Añadir eventos para controlar selección y actualizar visibilidad
		[...selectsMasculinos, ...selectsFemeninos].forEach((select) => {
			anteriores.set(select, ""); // valor inicial vacío

			select.addEventListener("change", (event) => {
				const actual = event.target.value.toString();
				const anterior = anteriores.get(select);
				const esTipoC = select.name === "C";

				console.log(
					`Cambio en select name="${select.name}": anterior="${anterior}" -> actual="${actual}"`,
				);

				// Quitar la selección anterior de los sets correspondientes
				if (anterior) {
					if (esTipoC) {
						seleccionadosTipoC.delete(anterior);
						console.log(`Quitado de seleccionadosTipoC: ${anterior}`);
					} else {
						seleccionadosGenerales.delete(anterior);
						console.log(`Quitado de seleccionadosGenerales: ${anterior}`);
					}
				}

				// Añadir la nueva selección
				if (actual) {
					if (esTipoC) {
						seleccionadosTipoC.add(actual);
						console.log(`Añadido a seleccionadosTipoC: ${actual}`);
					} else {
						seleccionadosGenerales.add(actual);
						console.log(`Añadido a seleccionadosGenerales: ${actual}`);
					}
				}

				anteriores.set(select, actual); // actualizar valor anterior
				actualizarSelects(); // actualizar opciones visibles
			});
		});

		actualizarSelects(); // Inicializa el estado
	} catch (error) {
		console.error("Error al rellenar los selects con alumnos:", error);
	}
}

/**
 * Rellena los selects con alumnos ya seleccionados previamente, permitiendo editar la selección,
 * y evita que se repitan alumnos en distintos selects.
 *
 * @param {string|number} idClase - Identificador de la clase para obtener alumnos y seleccionados.
 * @returns {Promise<void>}
 */
async function rellenarSelectsConSeleccionados(idClase) {
	try {
		const modelo = new M_obtenerAlumnos();
		const alumnos = await modelo.obtenerAlumnos(idClase);

		const response = await fetch(
			"/InscripcionesEVG/index.php?controlador=alumnosSeleccionados&accion=extraer&j=1",
			{
				method: "POST",
				headers: { "Content-Type": "application/json" },
				body: JSON.stringify({ idClase }),
			},
		);
		const seleccionados = await response.json();

		const contenedorMasculino = document.getElementById(
			"camposPruebasMasculina",
		);
		const contenedorFemenino = document.getElementById("camposPruebasFemenina");

		if (!contenedorMasculino || !contenedorFemenino) {
			console.warn("Contenedores no encontrados.");
			return;
		}

		const selectsMasculinos = contenedorMasculino.querySelectorAll("select");
		const selectsFemeninos = contenedorFemenino.querySelectorAll("select");

		const seleccionadosGenerales = new Set();
		const seleccionadosTipoC = new Set();
		const anteriores = new Map();

		/**
		 * Actualiza la visibilidad de las opciones en los selects para evitar duplicados.
		 */
		function actualizarSelects() {
			[...selectsMasculinos, ...selectsFemeninos].forEach((select) => {
				const options = select.querySelectorAll("option");
				const esTipoC = select.name === "C";

				options.forEach((option) => {
					const alumnoId = option.value;
					if (!alumnoId) return;

					if (esTipoC) {
						option.style.display =
							seleccionadosTipoC.has(alumnoId) &&
							anteriores.get(select) !== alumnoId
								? "none"
								: "";
					} else {
						option.style.display =
							seleccionadosGenerales.has(alumnoId) &&
							anteriores.get(select) !== alumnoId
								? "none"
								: "";
					}
				});
			});
		}

		/**
		 * Rellena un conjunto de selects filtrando por sexo y controlando los alumnos usados.
		 *
		 * @param {NodeListOf<HTMLSelectElement>} selects - Selects a rellenar.
		 * @param {string} sexo - Sexo de los alumnos a mostrar ("M" o "F").
		 */
		function rellenarSelects(selects, sexo) {
			const usadosPorPruebaTipo = new Map();

			const selectsPorPrueba = new Map();
			selects.forEach((select) => {
				const idPrueba = select.getAttribute("data-idprueba");
				if (!selectsPorPrueba.has(idPrueba)) {
					selectsPorPrueba.set(idPrueba, []);
				}
				selectsPorPrueba.get(idPrueba).push(select);
			});

			selectsPorPrueba.forEach((selectsPrueba, idPrueba) => {
				const selectsPorTipo = new Map();
				selectsPrueba.forEach((sel) => {
					const tipo = sel.name;
					if (!selectsPorTipo.has(tipo)) selectsPorTipo.set(tipo, []);
					selectsPorTipo.get(tipo).push(sel);
				});

				selectsPorTipo.forEach((selectsTipo, tipo) => {
					const keyPruebaTipo = `${idPrueba}_${tipo}`;
					if (!usadosPorPruebaTipo.has(keyPruebaTipo))
						usadosPorPruebaTipo.set(keyPruebaTipo, new Set());

					const usados = usadosPorPruebaTipo.get(keyPruebaTipo);

					selectsTipo.forEach((select, idx) => {
						select.innerHTML = `<option value="">Selecciona</option>`;
						alumnos
							.filter(
								(a) => a.sexo === sexo && !usados.has(a.idAlumno.toString()),
							)
							.forEach((alumno) => {
								const option = document.createElement("option");
								option.value = alumno.idAlumno;
								option.textContent = alumno.nombre;
								select.appendChild(option);
							});
					});
				});
			});
		}

		// Inicializamos los sets con los alumnos ya seleccionados
		seleccionados.forEach(({ idAlumno, tipo }) => {
			if (tipo === "C") {
				seleccionadosTipoC.add(idAlumno.toString());
			} else {
				seleccionadosGenerales.add(idAlumno.toString());
			}
		});

		// Rellenar selects masculinos y femeninos
		rellenarSelects(selectsMasculinos, "M");
		rellenarSelects(selectsFemeninos, "F");

		// Asignar los valores seleccionados previamente a cada select
		seleccionados.forEach(({ idAlumno, idPrueba, tipo }) => {
			const selector = `select[name="${tipo}"][data-idprueba="${idPrueba}"]`;
			const select = document.querySelector(selector);
			if (select) {
				select.value = idAlumno;
				anteriores.set(select, idAlumno.toString());
			}
		});

		/**
		 * Función para actualizar el conjunto de seleccionados y la visibilidad.
		 */
		function onChangeSelect(event) {
			const select = event.target;
			const actual = select.value.toString();
			const anterior = anteriores.get(select);
			const esTipoC = select.name === "C";

			console.log(
				`Cambio en select name="${select.name}": anterior="${anterior}" -> actual="${actual}"`,
			);

			if (anterior) {
				if (esTipoC) {
					seleccionadosTipoC.delete(anterior);
					console.log(`Quitado de seleccionadosTipoC: ${anterior}`);
				} else {
					seleccionadosGenerales.delete(anterior);
					console.log(`Quitado de seleccionadosGenerales: ${anterior}`);
				}
			}
			if (actual) {
				if (esTipoC) {
					seleccionadosTipoC.add(actual);
					console.log(`Añadido a seleccionadosTipoC: ${actual}`);
				} else {
					seleccionadosGenerales.add(actual);
					console.log(`Añadido a seleccionadosGenerales: ${actual}`);
				}
			}
			anteriores.set(select, actual);
			actualizarSelects();
		}

		[...selectsMasculinos, ...selectsFemeninos].forEach((select) => {
			select.addEventListener("change", onChangeSelect);
		});

		actualizarSelects();
	} catch (error) {
		console.error("Error al rellenar selects con seleccionados:", error);
	}
}

/**
 * Genera y descarga un fichero Excel con las inscripciones de la clase especificada.
 *
 * @param {string|number} idClase - Identificador de la clase para obtener inscripciones.
 * @returns {Promise<void>}
 */
async function generarExcelInscripciones(idClase) {
	try {
		const modelo = new M_obtenerAlumnos();
		const inscripciones = await modelo.obtenerInscripciones(idClase);

		if (!inscripciones.length) {
			ModalConfirmacion.mostrar(
				"Atención",
				"No hay inscripciones para esta clase.",
				"info",
			);
			return;
		}

		const titulo = `Inscripciones de la clase ${idClase}`;
		const filas = inscripciones.map((insc) => [
			insc.nombreAlumno,
			insc.email,
			insc.telefono,
			insc.fechaInscripcion,
		]);

		// Aquí deberías implementar la lógica para generar el Excel con la librería que uses.
		// Ejemplo (con SheetJS o similar) no incluido porque depende de tus dependencias.

		ModalConfirmacion.mostrar(
			"Éxito",
			`Archivo Excel generado para la clase ${idClase}.`,
			"success",
		);
	} catch (error) {
		console.error("Error al generar Excel de inscripciones:", error);
		ModalConfirmacion.mostrar(
			"Error",
			"Ha ocurrido un error al generar el Excel.",
			"error",
		);
	}
}

export {
	rellenarSelectsConAlumnos,
	rellenarSelectsConSeleccionados,
	generarExcelInscripciones,
};