package es.pulsoft.dao;

import java.util.List;

import javax.transaction.Transactional;

import org.hibernate.Session;
import org.hibernate.SessionFactory;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import es.pulsoft.controlador.entity.Director;
import es.pulsoft.controlador.entity.Escuela;

/**
 * Clase DAO para gestionar las operaciones relacionadas con la entidad Escuela.
 * Implementa la interfaz EscuelaDao.
 * Las operaciones incluyen obtener directores sin escuela, insertar, obtener, eliminar y buscar escuelas.
 */
@Repository
public class EscuelaDaoClase implements EscuelaDao {

    @Autowired 
    public SessionFactory sessionFactory;

    /**
     * Obtiene una lista de directores que no están asignados a ninguna escuela.
     * 
     * @return una lista de objetos Director que no tienen ninguna escuela asignada.
     */
    @Override
    @Transactional
    public List<Director> obtenerDirectores() {
        List<Director> listaDirectores = null;
        try {
            // Obtiene la sesión actual de Hibernate
            Session session = sessionFactory.getCurrentSession();
            // Ejecuta la consulta HQL para obtener directores que no están asignados a ninguna escuela
            listaDirectores = session.createQuery(
                "FROM Director d WHERE NOT EXISTS " +
                "(FROM Escuela e WHERE e.director = d ) order by nombre", 
                Director.class
            ).getResultList();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return listaDirectores;
    }

    /**
     * Inserta o actualiza una escuela en la base de datos.
     * 
     * @param escuela el objeto Escuela que se va a insertar o actualizar.
     */
    @Override
    @Transactional
    public void insertarEscuela(Escuela escuela) {
        try {
            // Obtiene la sesión actual de Hibernate
            Session session = sessionFactory.getCurrentSession();
            // Guarda o actualiza la escuela en la base de datos
            session.saveOrUpdate(escuela);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Obtiene una lista de todas las escuelas en la base de datos.
     * 
     * @return una lista de objetos Escuela.
     */
    @Override
    @Transactional
    public List<Escuela> obternerEscuelas() {
        Session session = sessionFactory.getCurrentSession();
        List<Escuela> listaEscuelas = null;
        try {
            // Ejecuta la consulta HQL para obtener todas las escuelas
            listaEscuelas = session.createQuery("from Escuela", Escuela.class).getResultList();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return listaEscuelas;
    }

    /**
     * Elimina una escuela de la base de datos.
     * Primero desvincula al director de la escuela y luego elimina la escuela.
     * 
     * @param id el ID de la escuela que se va a eliminar.
     */
    @Override
    @Transactional
    public void borrarEscuela(int id) {
        Session session = sessionFactory.getCurrentSession();
        Escuela escuela = session.get(Escuela.class, id);
        try {
            // Desvincula el director de la escuela
            Director director = escuela.getDirector();
            if (director != null) {
                director.setEscuela(null); // Rompe la relación inversa
                escuela.setDirector(null); // Rompe la relación principal
                session.update(director); // Actualiza el director
            }
            // Elimina la escuela
            session.delete(escuela);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * Obtiene una escuela por su ID.
     * 
     * @param id el ID de la escuela a obtener.
     * @return el objeto Escuela correspondiente al ID proporcionado, o null si no se encuentra.
     */
    @Override
    @Transactional
    public Escuela obtenerEscuela(int id) {
        Session session = sessionFactory.getCurrentSession();
        try {
            // Obtiene la escuela por su ID
            Escuela escuela = session.get(Escuela.class, id);
            return escuela;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * Realiza una búsqueda de escuelas basándose en un campo y valor de búsqueda.
     * Si el tipo de búsqueda es "director", busca por el nombre del director asociado.
     * 
     * @param tipo el campo en el que se realizará la búsqueda (por ejemplo, "nombre").
     * @param valor el valor que se busca en el campo especificado.
     * @return una lista de objetos Escuela que coinciden con los criterios de búsqueda.
     */
    @Override
    @Transactional
    public List<Escuela> obternerEscuelasBusqueda(String tipo, String valor) {
        Session session = sessionFactory.getCurrentSession();
        List<Escuela> listaEscuelas = null;
        try {
            // Realiza la búsqueda dependiendo del campo
            if (!tipo.endsWith("director")) {
                listaEscuelas = session.createQuery("from Escuela where lower(" + tipo + ")  like :valor", Escuela.class)
                        .setParameter("valor", valor + "%")
                        .getResultList();
            } else {
                listaEscuelas = session.createQuery(
                        "FROM Escuela WHERE director.nombre LIKE :valor", 
                        Escuela.class)
                        .setParameter("valor", valor + "%")
                        .getResultList();
            }
            return listaEscuelas;
        } catch (Exception e) {
            e.printStackTrace();
            return listaEscuelas;
        }
    }
}
