#include "Calendario.h"



Calendario::Calendario() : usuario(nullptr), gestorDatos("datos_planner.json") {
    clearAllData();
}

Calendario::~Calendario() {
    delete usuario;
    usuario = nullptr; // Asegura puntero nulo
    clearRamos();
    clearEvents();
    clearSemestres();
    clearActividadesDiarias(); 
}

// Métodos para liberar la memoria de las listas de objetos
void Calendario::clearRamos() {
    for (Ramo* ramo : ramos) {
        delete ramo; // Libera cada objeto Ramo
    }
    ramos.clear(); // Limpia la QList
    // Opcional: Ramo::resetNextId(); // Descomentar si implementas resetNextId() en la clase Ramo
}

void Calendario::clearEvents() {
    for (ActividadAcademica* evento : eventos) {
        delete evento; // Libera cada objeto EventoAcademico (polimórficamente)
    }
    eventos.clear();
    // Opcional: EventoAcademico::resetNextId(); // Descomentar si implementas resetNextId()
}

void Calendario::clearSemestres() {
    for (Semestre* semestre : semestres) {
        delete semestre; // Libera cada objeto Semestre
    }
    semestres.clear();
    // Opcional: Semestre::resetNextId(); // Descomentar si implementas resetNextId()
}

// Método para resetear todos los contadores de ID estáticos de las clases
// Esto es crucial para evitar IDs duplicados al cargar y luego añadir nuevos objetos.
void Calendario::resetAllNextIds() {
    // ¡IMPORTANTE! Debes implementar un método estático 'resetNextId()'
    // y, idealmente, un 'setNextId(int lastId)' en CADA CLASE
    // (Usuario, Ramo, EventoAcademico, Hito, BloqueHorario, Semestre, ActividadEvaluativa)
    // que use un 'static int nextId'.

    // Ejemplo (descomentar y usar si se implementan):
    /*
    Usuario::resetNextId();
    Ramo::resetNextId();
    EventoAcademico::resetNextId();
    Hito::resetNextId();
    BloqueHorario::resetNextId();
    Semestre::resetNextId();
    ActividadEvaluativa::resetNextId();
    */
    qDebug() << "Contadores de ID estáticos reseteados (si implementados).";
}

// Limpia todos los datos y reinicia el sistema a un estado por defecto.
void Calendario::clearAllData() {
    qDebug() << "Iniciando limpieza completa de datos en Calendario...";
    delete usuario;
    usuario = nullptr;
    clearRamos();
    clearEvents();
    clearSemestres();
    clearActividadesDiarias(); // ¡Llamada al nuevo clear!
    resetAllNextIds();
    inicializarUsuario("Estudiante Universitario", "estudiante@mail.com", "Ingeniería");
    qDebug() << "Limpieza completa finalizada. Datos en memoria reseteados.";
}

// --- Métodos de gestión de Usuario ---
// ¡CORREGIDO! Asegúrate de que esta implementación existe.
void Calendario::inicializarUsuario(const QString& nombre, const QString& email, const QString& carrera) {
    if (usuario) {
        delete usuario;
    }
    // Suponemos que el ID 0 indica que se debe generar un nuevo ID automáticamente por el constructor de Usuario.
    usuario = new Usuario(0, nombre, email, carrera);
    qDebug() << "Usuario inicializado:" << usuario->getNombre();
}

// Getters
Usuario* Calendario::getUsuario() const {
    return usuario;
}

// Setters
void Calendario::setUsuario(Usuario* user) {
    if (this->usuario) {
        delete this->usuario; // Liberar el usuario actual si existe
    }
    this->usuario = user; // Asignar el nuevo usuario (su memoria ahora es responsabilidad de Calendario)
    qDebug() << "Usuario de Calendario establecido a:" << (user ? user->getNombre() : "NULO");
}

// --- Métodos de gestión de Semestres ---
void Calendario::agregarSemestre(Semestre* semestre) {
    if (semestre) {
        semestres.append(semestre);
        qDebug() << "Semestre agregado:" << semestre->getNombre() << " (ID:" << semestre->getIdSemestre() << ")";
    }
}

void Calendario::eliminarSemestre(int idSemestre) {
    for (int i = 0; i < semestres.size(); ++i) {
        if (semestres.at(i)->getIdSemestre() == idSemestre) {
            delete semestres.at(i);
            semestres.removeAt(i);
            qDebug() << "Semestre con ID" << idSemestre << "eliminado.";
            // Considerar también la lógica de qué hacer con los ramos asociados a este semestre.
            // Esto es responsabilidad de la lógica de negocio superior (ej. UI o una clase GestorAcademico)
            return;
        }
    }
    qWarning() << "Semestre con ID" << idSemestre << "no encontrado para eliminar.";
}

// ¡CORREGIDO! Asegúrate de que esta implementación existe.
Semestre* Calendario::obtenerSemestrePorId(int idSemestre) const {
    for (Semestre* semestre : semestres) {
        if (semestre->getIdSemestre() == idSemestre) {
            return semestre;
        }
    }
    return nullptr;
}

QList<Semestre*> Calendario::getSemestres() const {
    return semestres;
}

void Calendario::setSemestres(const QList<Semestre*>& semestresList) {
    clearSemestres(); // Primero, liberar y limpiar cualquier semestre existente
    for (Semestre* sem : semestresList) {
        semestres.append(sem); // Añadir los nuevos semestres. Asumimos que su memoria será gestionada por Calendario.
        // Opcional: Semestre::setNextId(sem->getIdSemestre()); // Actualizar nextId si implementado
    }
    qDebug() << "Semestres establecidos. Total:" << semestres.size();
}

// --- Métodos de Gestión de Ramos ---
void Calendario::agregarRamo(Ramo* ramo) {
    if (ramo) {
        ramos.append(ramo);
        qDebug() << "Ramo agregado:" << ramo->getNombre() << " (ID:" << ramo->getIdRamo() << ")";
    }
}

void Calendario::eliminarRamo(int idRamo) {
    for (int i = 0; i < ramos.size(); ++i) {
        if (ramos.at(i)->getIdRamo() == idRamo) {
            delete ramos.at(i);
            ramos.removeAt(i);
            qDebug() << "Ramo con ID" << idRamo << "eliminado.";
            return;
        }
    }
    qWarning() << "Ramo con ID" << idRamo << "no encontrado para eliminar.";
}

Ramo* Calendario::obtenerRamoPorId(int idRamo) const {
    for (Ramo* ramo : ramos) {
        if (ramo->getIdRamo() == idRamo) {
            return ramo;
        }
    }
    return nullptr;
}

QList<Ramo*> Calendario::getRamos() const {
    return ramos;
}

void Calendario::setRamos(const QList<Ramo*>& ramosList) {
    clearRamos(); // Limpiar y liberar los existentes
    for (Ramo* ramo : ramosList) {
        ramos.append(ramo);
        // Opcional: Ramo::setNextId(ramo->getIdRamo());
    }
    qDebug() << "Ramos establecidos. Total:" << ramos.size();
}


void Calendario::agregarEvento(ActividadAcademica* evento) {
    if (evento) {
        eventos.append(evento);
        qDebug() << "Evento agregado:" << evento->getNombre() << " (ID:" << evento->getId() << ", Tipo:" << evento->obtenerTipoActividad() << ")";
    }
}

void Calendario::eliminarEvento(int idEvento) {
    for (int i = 0; i < eventos.size(); ++i) {
        if (eventos.at(i)->getId() == idEvento) { // Usar getId() de ActividadAcademica
            delete eventos.at(i);
            eventos.removeAt(i);
            qDebug() << "Evento con ID" << idEvento << "eliminado.";
            return;
        }
    }
    qWarning() << "Evento con ID" << idEvento << "no encontrado para eliminar.";
}

ActividadAcademica* Calendario::obtenerEventoPorId(int idEvento) const {
    for (ActividadAcademica* evento : eventos) {
        if (evento->getId() == idEvento) { // Usar getId()
            return evento;
        }
    }
    return nullptr;
}

QList<ActividadAcademica*> Calendario::getEvents() const { // Renombrado de getEventos()
    return eventos;
}

void Calendario::setEvents(const QList<ActividadAcademica*>& eventosList) { // Renombrado de setEventos()
    clearEvents(); // Usar el nuevo clearEvents()
    for (ActividadAcademica* evento : eventosList) {
        eventos.append(evento);
        // Opcional: ActividadAcademica::setNextId(evento->getId());
    }
    qDebug() << "Eventos establecidos. Total:" << eventos.size();
}

QList<ActividadAcademica*> Calendario::obtenerEventosParaFecha(const QDate& fecha) const {
    QList<ActividadAcademica*> eventosDelDia;
    for (ActividadAcademica* evento : eventos) {
        if (evento->getFechaInicio() == fecha || evento->getFechaFin() == fecha) {
            eventosDelDia.append(evento);
        }
    }
    return eventosDelDia;
}

QList<ActividadAcademica*> Calendario::obtenerEventsPorRamo(int idRamo) const { // Renombrado
    QList<ActividadAcademica*> eventosDelRamo;
    for (ActividadAcademica* evento : eventos) {
        if (evento->getRamoAsociado() && evento->getRamoAsociado()->getIdRamo() == idRamo) {
            eventosDelRamo.append(evento);
        }
    }
    return eventosDelRamo;
}

// Este método sigue devolviendo Tarea* pero ahora Tarea hereda de ActividadAcademica
QList<Tarea*> Calendario::obtenerTareasPendientes() const {
    QList<Tarea*> tareasPendientes;
    for (ActividadAcademica* evento : eventos) {
        if (Tarea* tarea = dynamic_cast<Tarea*>(evento)) {
            if (!tarea->estaCompletada()) {
                tareasPendientes.append(tarea);
            }
        }
    }
    return tareasPendientes;
}


void Calendario::clearActividadesDiarias() {
    for (ActividadDiaria* act : actividadesDiarias) {
        delete act;
    }
    actividadesDiarias.clear();
    // Opcional: ActividadDiaria::resetNextId();
}
void Calendario::agregarActividadDiaria(ActividadDiaria* actividad) {
    if (actividad) {
        actividadesDiarias.append(actividad);
        qDebug() << "Actividad Diaria agregada:" << actividad->getNombre() << " (ID:" << actividad->getId() << ")";
    }
}

void Calendario::eliminarActividadDiaria(int idActividad) {
    for (int i = 0; i < actividadesDiarias.size(); ++i) {
        if (actividadesDiarias.at(i)->getId() == idActividad) {
            delete actividadesDiarias.at(i);
            actividadesDiarias.removeAt(i);
            qDebug() << "Actividad Diaria con ID" << idActividad << "eliminada.";
            return;
        }
    }
    qWarning() << "Actividad Diaria con ID" << idActividad << "no encontrada para eliminar.";
}

ActividadDiaria* Calendario::obtenerActividadDiariaPorId(int idActividad) const {
    for (ActividadDiaria* actividad : actividadesDiarias) {
        if (actividad->getId() == idActividad) {
            return actividad;
        }
    }
    return nullptr;
}

QList<ActividadDiaria*> Calendario::getActividadesDiarias() const {
    return actividadesDiarias;
}

void Calendario::setActividadesDiarias(const QList<ActividadDiaria*>& actividadesList) {
    clearActividadesDiarias(); // Limpiar y liberar existentes
    for (ActividadDiaria* act : actividadesList) {
        actividadesDiarias.append(act);
        // Opcional: ActividadDiaria::setNextId(act->getId());
    }
    qDebug() << "Actividades Diarias establecidas. Total:" << actividadesDiarias.size();
}

// **MODIFICACIÓN CLAVE: generarToDoListSemanal()**
QList<ActividadDiaria*> Calendario::generarToDoListSemanal(const QDate& fechaReferencia) const {
    QList<ActividadDiaria*> toDoList;

    QDate semanaInicio = fechaReferencia.addDays(-(fechaReferencia.dayOfWeek() - 1)); // Lunes de la semana
    QDate semanaFin = semanaInicio.addDays(6); // Domingo de la semana

    qDebug() << "Generando To-Do List para la semana del" << semanaInicio.toString("dd/MM/yyyy") << "al" << semanaFin.toString("dd/MM/yyyy");

    // 1. Incorporar recordatorios de entregas (tareas, proyectos, certámenes)
    incorporarRecordatoriosDeEventos(toDoList, semanaInicio, semanaFin);

    // 2. Distribuir horas de avance para TAREAS Y PROYECTOS ESPECÍFICOS
    distribuirHorasDeAvanceEnEventos(toDoList, semanaInicio, semanaFin);

    // 3. Distribuir horas de estudio general y proyecto general del ramo
    distribuirHorasGeneralesDeRamo(toDoList, semanaInicio, semanaFin);

    // Ordenar la lista por fecha y hora de inicio
    std::sort(toDoList.begin(), toDoList.end(), [](const ActividadDiaria* a, const ActividadDiaria* b) {
        if (a->getFecha() != b->getFecha()) {
            return a->getFecha() < b->getFecha();
        }
        return true;// a->getHoraInicio() < b->getHoraInicio();
    });

    return toDoList;
}

// Helper: Carga máxima de horas SCT por crédito
float Calendario::getCargaMaximaSemanalRamo(const Ramo* ramo) const {
    if (!ramo) return 0.0f;
    // Asumimos 1.5 horas totales por crédito SCT a la semana
    return ramo->getCreditos() * HORAS_SCT_POR_CREDITO;
}


// --- Métodos Auxiliares para generarToDoListSemanal ---

void Calendario::distribuirHorasEstudio(QList<ActividadDiaria*>& toDoList, const QDate& semanaInicio, const QDate& semanaFin) const {
    for (Ramo* ramo : ramos) {
        if (!ramo || !ramo->getSemestreAsociado()) continue;
        if (ramo->getSemestreAsociado()->getFechaInicio() > semanaFin ||
            ramo->getSemestreAsociado()->getFechaFin() < semanaInicio) { continue; }

        float totalHorasEstudioRamo = ramo->getTotalHorasEstudioNoPresencial();
        if (totalHorasEstudioRamo <= 0) continue;

        float horasPorSemana = totalHorasEstudioRamo / static_cast<float>(ramo->getSemestreAsociado()->getNumeroSemanas());
        if (horasPorSemana <= 0) continue;

        int minutosAAsignarEstaSemana = static_cast<int>(horasPorSemana * 60);
        if (minutosAAsignarEstaSemana <= 0) continue;

        qDebug() << "Distribuyendo" << horasPorSemana << "horas/semana de estudio para" << ramo->getNombre();

        // Identificar tareas y certámenes pendientes del ramo en las próximas semanas
        QList<ActividadAcademica*> eventosPendientesRamo = obtenerEventsPorRamo(ramo->getIdRamo()); // Obtener ActividadAcademica*
        // Filtrar solo los no completados y ordenarlos por fecha de entrega más próxima
        std::sort(eventosPendientesRamo.begin(), eventosPendientesRamo.end(), [](const ActividadAcademica* a, const ActividadAcademica* b) {
            if (!a || !b) return false;
            return a->getFechaFin() < b->getFechaFin();
        });

        int minutosRestantesParaAsignar = minutosAAsignarEstaSemana;
        QDate diaActual = semanaInicio;

        for (ActividadAcademica* eventoProx : eventosPendientesRamo) { // Iterar sobre ActividadAcademica*
            if (eventoProx->estaCompletada()) continue; // Usar estaCompletada()

            if (eventoProx->getFechaFin() >= semanaInicio && eventoProx->getFechaFin() <= semanaInicio.addDays(13)) {
                
                int minutosBloque = 70;

                while (minutosRestantesParaAsignar > 0 && minutosBloque > 0 && diaActual <= semanaFin) {
                    if (diaActual.dayOfWeek() == Qt::Saturday || diaActual.dayOfWeek() == Qt::Sunday) {
                        diaActual = diaActual.addDays(1);
                        continue;
                    }
                    int minutosEsteBloque = qMin(minutosBloque, minutosRestantesParaAsignar);
                    toDoList.append(new ActividadDiaria(0, "Estudiar para " + eventoProx->getNombre(),
                                                          ActividadDiaria::EstudioPersonal,
                                                          diaActual, minutosEsteBloque, ramo, eventoProx->getDescripcion(), nullptr));
                    minutosRestantesParaAsignar -= minutosEsteBloque;
                    diaActual = diaActual.addDays(1);
                }
            }
        }
        // ... (código para distribuir minutos restantes uniformemente - sin cambios) ...
        if (minutosRestantesParaAsignar > 0) { /* ... */ }
    }
}

void Calendario::distribuirHorasProyectos(QList<ActividadDiaria*>& toDoList, const QDate& semanaInicio, const QDate& semanaFin) const {
    for (Ramo* ramo : ramos) {
        if (!ramo || !ramo->getSemestreAsociado()) continue;
        if (ramo->getSemestreAsociado()->getFechaInicio() > semanaFin ||
            ramo->getSemestreAsociado()->getFechaFin() < semanaInicio) { continue; }

        float totalHorasProyectosRamo = ramo->getTotalHorasProyectosNoPresencial();
        if (totalHorasProyectosRamo <= 0) continue;

        float horasPorSemana = totalHorasProyectosRamo / static_cast<float>(ramo->getSemestreAsociado()->getNumeroSemanas());
        if (horasPorSemana <= 0) continue;

        int minutosAAsignarEstaSemana = static_cast<int>(horasPorSemana * 60);
        if (minutosAAsignarEstaSemana <= 0) continue;

        qDebug() << "Distribuyendo" << horasPorSemana << "horas/semana de proyecto para" << ramo->getNombre();

        QList<ActividadAcademica*> proyectosPendientesRamo; // Usar ActividadAcademica*
        for (ActividadAcademica* evento : this->obtenerEventsPorRamo(ramo->getIdRamo())) { // Usar getEventsPorRamo
            if (Proyecto* p = dynamic_cast<Proyecto*>(evento)) {
                if (!p->estaCompletada()) { // Usar estaCompletada()
                    proyectosPendientesRamo.append(p);
                }
            }
        }
        std::sort(proyectosPendientesRamo.begin(), proyectosPendientesRamo.end(), [](const ActividadAcademica* a, const ActividadAcademica* b) {
            if (!a || !b) return false;
            return a->getFechaFin() < b->getFechaFin();
        });

        int minutosRestantesParaAsignar = minutosAAsignarEstaSemana;
        QDate diaActual = semanaInicio;

        for (ActividadAcademica* proyectoProx : proyectosPendientesRamo) { // Iterar sobre ActividadAcademica*
            if (proyectoProx->getFechaFin() >= semanaInicio && proyectoProx->getFechaFin() <= semanaInicio.addDays(13)) {
                int minutosBloque = qMin(minutosRestantesParaAsignar, 180);

                while (minutosRestantesParaAsignar > 0 && minutosBloque > 0 && diaActual <= semanaFin) {
                    if (diaActual.dayOfWeek() == Qt::Sunday) {
                        diaActual = diaActual.addDays(1);
                        continue;
                    }
                    int minutosEsteBloque = qMin(minutosBloque, minutosRestantesParaAsignar);
                    toDoList.append(new ActividadDiaria(0, "Trabajar en Proyecto: " + proyectoProx->getNombre(),
                                                          ActividadDiaria::TrabajoProyecto,
                                                          diaActual, minutosEsteBloque, ramo, proyectoProx->getDescripcion(), nullptr));
                    minutosRestantesParaAsignar -= minutosEsteBloque;
                    diaActual = diaActual.addDays(1);
                }
            }
        }
        // ... (código para distribuir minutos restantes uniformemente - sin cambios) ...
        if (minutosRestantesParaAsignar > 0) { /* ... */ }
    }
}
void Calendario::incorporarActividadesEvaluativasPendientes(QList<ActividadDiaria*>& toDoList, const QDate& semanaInicio, const QDate& semanaFin) const {
    // Recorrer TODOS los ramos
    for (Ramo* ramo : ramos) {
        if (!ramo) continue;

        // Recorrer las actividades evaluativas (ActividadAcademica*) de CADA ramo
        for (ActividadAcademica* actividadEval : ramo->getActividadesEvaluativas()) {
            if (!actividadEval || actividadEval->estaCompletada()) continue; // Solo actividades evaluativas no completadas

            QDate fechaActividad = actividadEval->getFechaFin(); // Usamos la fecha de fin (entrega/realización)

            // Si la actividad evaluativa cae dentro de la semana actual o la semana anterior (para no perderla de vista)
            if ((fechaActividad >= semanaInicio && fechaActividad <= semanaFin) ||
                (fechaActividad < semanaInicio && fechaActividad >= semanaInicio.addDays(-7)))
            {
                ActividadDiaria::TipoActividad tipoAct = ActividadDiaria::OtraActividad;
                QString nombreAct = actividadEval->getNombre();
                int duracionMin = 60; // Duración por defecto si no se puede estimar mejor.

                // Determinar el tipo de actividad diaria y duración/nombre específicos
                if (Tarea* tarea = dynamic_cast<Tarea*>(actividadEval)) {
                    tipoAct = ActividadDiaria::TareaEspecifica;
                    duracionMin = static_cast<int>(tarea->getEstimacionHoras() * 60); // Horas estimadas de la tarea
                    nombreAct = "Entregar Tarea: " + tarea->getNombre();
                } else if (Proyecto* proyecto = dynamic_cast<Proyecto*>(actividadEval)) {
                    tipoAct = ActividadDiaria::TrabajoProyecto;
                    nombreAct = "Fecha Límite Proyecto: " + proyecto->getNombre();
                    duracionMin = 15; // Recordatorio corto
                } else if (Certamen* certamen = dynamic_cast<Certamen*>(actividadEval)) {
                    tipoAct = ActividadDiaria::OtraActividad; // Podrías usar un tipo más específico como "CertamenProgramado"
                    nombreAct = "Certamen: " + certamen->getNombre();
                    duracionMin = 70 / 60; // Duración real del certamen
                } else {
                    // Este caso cubre las ActividadAcademica genéricas (ej. definidas en AddRamoDialog)
                    // que no son Tarea, Proyecto, o Certamen específicos.
                    tipoAct = ActividadDiaria::OtraActividad; // Tipo genérico
                    nombreAct = "Evaluación: " + actividadEval->getNombre();
                    // duracionMin se mantiene en 60 por defecto
                }

                // Añadir la actividad a la To-Do List
                toDoList.append(new ActividadDiaria(0, nombreAct, tipoAct,
                                                      fechaActividad, duracionMin, actividadEval->getRamoAsociado(), actividadEval->getDescripcion(), nullptr));
            }
        }
    }
}



// **MODIFICADA FUNCIÓN**: incorporarRecordatoriosDeEventos
// Antes llamada incorporarTareasPendientes
void Calendario::incorporarRecordatoriosDeEventos(QList<ActividadDiaria*>& toDoList, const QDate& semanaInicio, const QDate& semanaFin) const {
    // Recorrer TODOS los eventos globales (que incluyen Tareas, Proyectos, Certámenes y Evaluaciones Genéricas)
    for (ActividadAcademica* evento : eventos) {
        if (!evento || evento->estaCompletada()) continue;

        QDate fechaRelevante = evento->getFechaFin(); // Usamos fechaFin para la entrega/realización

        // Si el evento cae dentro de la semana actual o la semana anterior (para no perderlo de vista)
        if ((fechaRelevante >= semanaInicio && fechaRelevante <= semanaFin) ||
            (fechaRelevante < semanaInicio && fechaRelevante >= semanaInicio.addDays(-7)))
        {
            ActividadDiaria::TipoActividad tipoAct = ActividadDiaria::OtraActividad;
            QString nombreAct = evento->getNombre();
            int duracionMin = 30; // Duración por defecto para un recordatorio
            QTime horaSugerida = QTime(8, 0);

            if (Tarea* tarea = dynamic_cast<Tarea*>(evento)) {
                tipoAct = ActividadDiaria::TareaEspecifica;
                nombreAct = "Recordatorio: Entregar Tarea: " + tarea->getNombre();
                //horaSugerida = tarea->getHoraEntrega();
                duracionMin = 15; // Un recordatorio corto de entrega
            } else if (Proyecto* proyecto = dynamic_cast<Proyecto*>(evento)) {
                tipoAct = ActividadDiaria::TrabajoProyecto;
                nombreAct = "Recordatorio: Fecha Límite Proyecto: " + proyecto->getNombre();
                //horaSugerida = proyecto->getFechaFin().time();
                duracionMin = 15;
            } else if (Certamen* certamen = dynamic_cast<Certamen*>(evento)) {
                tipoAct = ActividadDiaria::OtraActividad; // O un tipo más específico "ExamenProgramado"
                nombreAct = "Recordatorio: Certamen: " + certamen->getNombre();
                //horaSugerida = certamen->getFechaInicio().time();
                duracionMin = 70;//certamen->getFechaInicio().secsTo(certamen->getFechaFin()) / 60; // Duración real del certamen
            } else {
                // Para ActividadAcademica genérica
                nombreAct = "Recordatorio: " + evento->getNombre();
                duracionMin = 15;
            }

            // ¡CORRECCIÓN CLAVE AQUÍ! Pasar horaSugerida como quinto argumento
            toDoList.append(new ActividadDiaria(0, nombreAct, tipoAct,
                                                  fechaRelevante, duracionMin, evento->getRamoAsociado(), evento->getDescripcion(), nullptr));
        }
    }
}
void Calendario::distribuirHorasDeAvanceEnEventos(QList<ActividadDiaria*>& toDoList, const QDate& semanaInicio, const QDate& semanaFin) const {
    // Usaremos un mapa temporal para llevar las horas ocupadas por cada ramo en la semana actual de generación.
    QMap<const Ramo*, float> horasOcupadasEnSemanaActualParaRamo;

    // 1. Recopilar Tareas y Proyectos pendientes (ActividadAcademica) de TODOS los ramos
    QList<ActividadAcademica*> tareasYProyectosPendientes;
    for (Ramo* ramo : ramos) {
        if (!ramo) continue;
        for (ActividadAcademica* act : ramo->getActividadesEvaluativas()) {
            if (!act || act->estaCompletada()) continue;

            if (dynamic_cast<Tarea*>(act) || dynamic_cast<Proyecto*>(act)) {
                if (act->getEstimacionHoras() > 0.01f) {
                    tareasYProyectosPendientes.append(act);
                }
            }
        }
    }

    // 2. Ordenar por fecha de entrega más próxima (priorizar lo más urgente)
    std::sort(tareasYProyectosPendientes.begin(), tareasYProyectosPendientes.end(), [](const ActividadAcademica* a, const ActividadAcademica* b) {
        if (!a || !b) return false;
        return a->getFechaFin() < b->getFechaFin();
    });

    const int MAX_EVENTOS_A_PLANIFICAR = 2; // Definimos que solo planificaremos los 2 eventos siguientes
    int eventosProcesados = 0;

    for (ActividadAcademica* evento : tareasYProyectosPendientes) {
        if (eventosProcesados >= MAX_EVENTOS_A_PLANIFICAR) {
            break;
        }

        if (!evento || evento->estaCompletada()) continue;

        Ramo* ramo = evento->getRamoAsociado();
        if (!ramo) continue;

        // Declarar horasEstimadasRestantes aquí
        float horasEstimadasRestantes = evento->getEstimacionHoras();
        if (horasEstimadasRestantes <= 0.01f) continue;

        float cargaMaximaSemanalRamo = getCargaMaximaSemanalRamo(ramo);
        if (cargaMaximaSemanalRamo <= 0.01f) {
            qDebug() << "Ramo" << ramo->getNombre() << "no tiene carga SCT válida. No se asignarán horas de avance.";
            continue;
        }

        qDebug() << "Planificando avance para: " << evento->getNombre() << " (Ramo: " << ramo->getNombre() << "), quedan " << horasEstimadasRestantes << "h";

        QDate fechaEntrega = evento->getFechaFin();
        QDate fechaActualRetro = semanaFin; // Comenzar la planificación desde el final de la semana actual

        // Retro-planificar hasta la semana actual o hasta que las horas se agoten
        while (horasEstimadasRestantes > 0.01f && fechaActualRetro >= semanaInicio) { // Usar horasEstimadasRestantes
            // Declarar semanaDePlanificacion y finDeSemanaDePlanificacion aquí
            QDate semanaDePlanificacion = fechaActualRetro.addDays(-(fechaActualRetro.dayOfWeek() - 1)); // Lunes de la semana
            QDate finDeSemanaDePlanificacion = semanaDePlanificacion.addDays(6); // Domingo de la semana
            QDate inicioDeSemanaActual = semanaInicio; // Lunes de la semana actual

            // Si la semana de planificación está fuera del semestre del ramo, o ya pasó, no planificar
            if (semanaDePlanificacion < ramo->getSemestreAsociado()->getFechaInicio() ||
                semanaDePlanificacion > ramo->getSemestreAsociado()->getFechaFin()) {
                fechaActualRetro = inicioDeSemanaActual.addDays(-1); // Mover a la semana anterior
                continue;
            }

            float horasYaOcupadasEsteRamoEstaSemana = horasOcupadasEnSemanaActualParaRamo.value(ramo, 0.0f);
            float horasDisponiblesEsteRamoEstaSemana = cargaMaximaSemanalRamo - horasYaOcupadasEsteRamoEstaSemana;

            if (horasDisponiblesEsteRamoEstaSemana <= 0.01f) {
                fechaActualRetro = inicioDeSemanaActual.addDays(-1);
                continue;
            }

            float horasAAsignarEnEstaSemana = 0.0f;
            if (fechaEntrega <= finDeSemanaDePlanificacion) { // Si la entrega es esta semana o antes
                horasAAsignarEnEstaSemana = horasEstimadasRestantes; // Asignar todas las restantes para finalizar
            } else { // Si la entrega es en una semana futura, distribuir equitativamente
                int semanasHastaEntregaDesdeEstaSemana = (semanaDePlanificacion.daysTo(fechaEntrega) / 7) + 1;
                if (semanasHastaEntregaDesdeEstaSemana <= 0) semanasHastaEntregaDesdeEstaSemana = 1;
                horasAAsignarEnEstaSemana = horasEstimadasRestantes / semanasHastaEntregaDesdeEstaSemana;
            }

            horasAAsignarEnEstaSemana = qMin(horasAAsignarEnEstaSemana, horasDisponiblesEsteRamoEstaSemana);
            // Asegurarse de no exceder las horas restantes del evento (usar horasEstimadasRestantes)
            horasAAsignarEnEstaSemana = qMin(horasAAsignarEnEstaSemana, horasEstimadasRestantes); // <-- CORRECCIÓN

            horasAAsignarEnEstaSemana = qFloor(horasAAsignarEnEstaSemana * 2.0f) / 2.0f; // Redondear a múltiplo de 0.5h

            if (horasAAsignarEnEstaSemana > 0.01f) {
                int minutosBloque = static_cast<int>(horasAAsignarEnEstaSemana * 60);

                QDate diaAsignacion = semanaDePlanificacion.addDays(1); // Martes
                if (diaAsignacion.dayOfWeek() == Qt::Saturday || diaAsignacion.dayOfWeek() == Qt::Sunday) {
                    diaAsignacion = semanaDePlanificacion;
                    while (diaAsignacion.dayOfWeek() == Qt::Saturday || diaAsignacion.dayOfWeek() == Qt::Sunday) {
                        diaAsignacion = diaAsignacion.addDays(1);
                    }
                }
                if (diaAsignacion > fechaEntrega) { // No planificar después de la fecha de entrega
                    diaAsignacion = fechaEntrega;
                }

                QTime horaSugerida = QTime(18, 0); // Hora de inicio para bloques de avance

                toDoList.append(new ActividadDiaria(0, QString("Avanzar en %1").arg(evento->getNombre()),
                                                      ActividadDiaria::TareaEspecifica,
                                                      diaAsignacion, minutosBloque, ramo, evento->getDescripcion(), nullptr));
                horasEstimadasRestantes -= horasAAsignarEnEstaSemana; // Actualizar horas restantes del evento
                horasOcupadasEnSemanaActualParaRamo[ramo] += horasAAsignarEnEstaSemana;

                qDebug() << "  Asignado: " << horasAAsignarEnEstaSemana << "h en semana de " << semanaDePlanificacion.toString("dd/MM") << ". Restan al evento: " << horasEstimadasRestantes << "h.";
            }
            fechaActualRetro = semanaDePlanificacion.addDays(-1); // Mover a la semana anterior
        }
        if (horasEstimadasRestantes > 0.01f) {
            qDebug() << "No se pudieron asignar todas las horas de avance para" << evento->getNombre() << ". Quedan " << horasEstimadasRestantes << "h sin planificar.";
        }
        eventosProcesados++; // Contar el evento procesado
    }
}

// **MODIFICADA FUNCIÓN**: distribuirHorasGeneralesDeRamo
void Calendario::distribuirHorasGeneralesDeRamo(QList<ActividadDiaria*>& toDoList, const QDate& semanaInicio, const QDate& semanaFin) const {
    // Para una gestión de carga más estricta, necesitaríamos un mapa de horas ocupadas persistente
    // que se actualice por distribuirHorasDeAvanceEnEventos. Por ahora, esto es general.
    for (Ramo* ramo : ramos) {
        if (!ramo || !ramo->getSemestreAsociado()) continue;

        if (ramo->getSemestreAsociado()->getFechaInicio() > semanaFin ||
            ramo->getSemestreAsociado()->getFechaFin() < semanaInicio) {
            continue;
        }

        // Horas semanales prorrateadas del total para estudio y proyectos generales
        float horasEstudioPorSemana = ramo->getTotalHorasEstudioNoPresencial() / static_cast<float>(ramo->getSemestreAsociado()->getNumeroSemanas());
        float horasProyectosPorSemana = ramo->getTotalHorasProyectosNoPresencial() / static_cast<float>(ramo->getSemestreAsociado()->getNumeroSemanas());

        // Distribuir horas de Estudio Personal General
        if (horasEstudioPorSemana > 0.01f) {
            int minutosEstudio = static_cast<int>(horasEstudioPorSemana * 60);
            int diasHabiles = 5; // L-V
            int minutosPorDia = minutosEstudio / diasHabiles;
            int minutosRestantes = minutosEstudio % diasHabiles;

            QDate diaActual = semanaInicio;
            QTime horaSugerida = QTime(17, 0); // Hora sugerida para estudio general

            for (int i = 0; i < diasHabiles; ++i) {
                if (diaActual.dayOfWeek() == Qt::Saturday || diaActual.dayOfWeek() == Qt::Sunday) {
                    diaActual = diaActual.addDays(1);
                    continue;
                }
                int minutosHoy = minutosPorDia;
                if (minutosRestantes > 0) { minutosHoy++; minutosRestantes--; }
                if (minutosHoy > 0) {
                    toDoList.append(new ActividadDiaria(0, "Estudio General " + ramo->getNombre(),
                                                          ActividadDiaria::EstudioPersonal,
                                                          diaActual, minutosHoy, ramo, "Bloque de estudio general.", nullptr));
                }
                diaActual = diaActual.addDays(1);
            }
        }

        // Distribuir horas de Proyecto General
        if (horasProyectosPorSemana > 0.01f) {
            int minutosProyecto = static_cast<int>(horasProyectosPorSemana * 60);
            QDate diaProyecto = semanaInicio.addDays(5); // Sábado
            QTime horaSugerida = QTime(10, 0); // Hora sugerida para proyecto general

            toDoList.append(new ActividadDiaria(0, "Trabajo General Proyecto " + ramo->getNombre(),
                                                  ActividadDiaria::TrabajoProyecto,
                                                  diaProyecto, minutosProyecto, ramo, "Bloque de trabajo general en proyecto.", nullptr));
        }
    }
}
