package es.uv.saic.domain;

import java.math.BigInteger;
import java.util.List;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import es.uv.saic.dto.TascaInformeTransferDTO;

@Repository
public interface InstanciaTascaRepository extends JpaRepository<InstanciaTasca, BigInteger> {
	
	@Query(nativeQuery=true, value=("""
		WITH x AS(SELECT id_tasca, max(version) AS version FROM tasquesi WHERE id_instancia = ?1 GROUP BY id_tasca) 
		SELECT ti.* FROM tasquesi ti, x WHERE ti.id_tasca = x.id_tasca AND ti.version = x.version AND id_instancia = ?1 ORDER BY id_tasca ASC; """))
	public List<InstanciaTasca> findByInstancia(BigInteger idInstancia);
	
	@Query(nativeQuery=true, value=("""
		SELECT ti.* FROM tasquesi ti 
		LEFT JOIN tasques ta ON ti.id_tasca = ta.id_tasca 
		WHERE id_instancia = ?1 AND id_tascap = ?2 
		ORDER BY version DESC LIMIT 1; """))
	public InstanciaTasca findByInstanciaTascap(BigInteger idInstancia, Integer tascap);
	
	@Query(nativeQuery=true, value=("""
		SELECT * FROM tasquesi WHERE id_instancia = ?1 AND id_tasca = ?2 AND version < ?3 ORDER BY data_fet DESC; """))
	public List<InstanciaTasca> findOlderVerions(BigInteger idInstancia, Integer idTasca, Integer version);
	
	@Query(nativeQuery=true, value=("""
		SELECT * FROM tasquesi WHERE id_instancia = ?1 AND estat = 'A' 
		AND version = (SELECT MAX(version) AS version FROM tasquesi WHERE id_instancia = ?1 AND estat = 'A'); """))
	public InstanciaTasca findActiveByInstancia(BigInteger idInstancia);
	
	@Query(nativeQuery=true, value=("""
		SELECT * FROM tasquesi WHERE estat  = 'A' AND id_tasca IN(SELECT id_tasca FROM tasques WHERE tipus = ?1)"""))
	public List<InstanciaTasca> findActivesByType(Integer type);
	
	@Query(nativeQuery=true, value=("""
		SELECT DISTINCT(ins.id_instancia) FROM instancies ins, usuaris_rols usr, tasques tas, tasquesi tasi 
		WHERE ins.estat = 'A' 
		AND ins.tlugar = usr.tlugar AND ins.lugar = usr.lugar 
		AND usr.vigent = TRUE AND usr.usuari = ?1 AND ins.id_instancia = tasi.id_instancia 
		AND tas.id_proces = ins.id_proces AND tas.id_rol = usr.id_rol 
		AND tas.id_tasca = tasi.id_tasca AND tasi.id_tascai = ?2; """))
	public BigInteger isUserAutorized(String usuari, BigInteger idTascai);
	
	@Query(nativeQuery=true, value=("""
		SELECT DISTINCT(ins.id_instancia) FROM instancies ins, usuaris_rols usr, tasques tas, tasquesi tasi, rols rl 
		WHERE ins.estat = 'A' AND ins.centre = usr.lugar 
		AND usr.vigent = TRUE AND usr.usuari = ?1 AND ins.id_instancia = tasi.id_instancia 
		AND tas.id_proces = ins.id_proces AND tas.id_rol = usr.id_rol 
		AND rl.id_rol = usr.id_rol AND rl.ambit = 'C' 
		AND tas.id_tasca = tasi.id_tasca AND tasi.id_tascai = ?2; """	))
	public BigInteger isUserAutorizedByAmbitC(String usuari, BigInteger idTascai);
	
	@Query("SELECT i FROM InstanciaTasca i WHERE i.instancia.centre = ?1 AND i.instancia.titulacio = ?2 AND i.tasca.proces.nomProces = ?3 AND i.estat = 'E' AND i.tasca.proces.cursAvaluat < ?4")
	public List<InstanciaTasca> findOlderByProces(Integer centre, Integer titulacio, String nomProces, Integer minCurs);

	@Query(nativeQuery=true, value=("""
		WITH x AS( 
			SELECT id_tasca AS id_current FROM tasques WHERE id_proces = ?2 AND id_tascap = ?3 
		) 
		SELECT * FROM tasquesi t, x WHERE id_instancia = ?1 AND t.id_tasca = x.id_current 
		AND version = (SELECT MAX(version) FROM tasquesi t, x WHERE t.id_tasca = x.id_current AND id_instancia = ?1); """))
	public InstanciaTasca findNext(BigInteger idInstancia, Integer idProces, Integer idTascap);
	
	@Query(nativeQuery=true, value=("""
		SELECT us.* FROM usuaris us, usuaris_rols usr, tasques tas, tasquesi tasi, instancies ins  
		WHERE us.usuari = usr.usuari AND tasi.id_tasca = tas.id_tasca AND tasi.estat = 'A' 
		AND ins.lugar = usr.lugar AND ins.tlugar = usr.tlugar AND ins.id_instancia = tasi.id_instancia AND ins.id_instancia = ?1 """))
	public List<Usuari> getUsers(BigInteger idInstancia);
	
	@Query(nativeQuery=true, value=("""
		SELECT ti.id_tascai, ti.id_instancia, ti.id_tasca, ti.version, ti.estat, ti.usuari_fet, ti.data_fet, ti.evidencia 
		FROM tasquesi ti, tasques ta   
		WHERE ti.id_tasca = ta.id_tasca AND ti.estat = 'A' AND ta.data_lim > NOW(); """))
	public List<InstanciaTasca> getPastTasks();
	
	@Query(nativeQuery=true, value=("""
		SELECT ti.* FROM tasquesi ti 
		JOIN tasques ta ON ta.id_tasca = ti.id_tasca 
		WHERE ti.id_instancia = ?1 AND ta.informe AND estat = 'E' 
		ORDER BY ta.id_tascap DESC, ti.version DESC  
		LIMIT 1; """))
	public InstanciaTasca getReportFromInstancia(BigInteger idInstancia);
	
	@Query(nativeQuery=true, value=("""
		SELECT ti.* FROM tasquesi ti LEFT JOIN tasques ta 
		ON ti.id_tasca = ta.id_tasca 
		WHERE ti.id_instancia = ( 
			SELECT id_instancia FROM instancies 
			WHERE id_proces = ?1 AND tlugar = ?2 AND lugar = ?3 
			AND centre = ?4 AND titulacio = ?5 AND estat = 'F' 
		) 
		AND ti.estat = 'E' AND ta.informe 
		ORDER BY ti.id_tascai DESC, ti.version DESC LIMIT 1; """))
	public InstanciaTasca getReportFromProcesOrgan(Integer idProces, String tlugar, Integer lugar,
												   Integer centre, Integer titulacio);

	@Query(nativeQuery=true, value=("""
		SELECT ti.* FROM tasquesi ti LEFT JOIN tasques ta 
		ON ti.id_tasca = ta.id_tasca 
		WHERE ti.id_instancia = ( 
				SELECT id_instancia FROM instancies ic 
				LEFT JOIN processos pr ON ic.id_proces = pr.id_proces 
				WHERE pr.nom_proces = ?1 AND ic.tlugar = ?2 AND ic.lugar = ?3 
				AND ic.centre = ?4 AND ic.titulacio = ?5 AND ic.estat = 'F' 
				ORDER BY pr.curs_avaluat DESC LIMIT 1 
			) 
		AND ti.estat = 'E' AND ta.informe 
		ORDER BY ti.id_tascai DESC, ti.version DESC LIMIT 1; """))
	public InstanciaTasca getReportFromNomProcesOrgan(String nomProces, String tlugar, Integer lugar,
												      Integer centre, Integer titulacio);
	
	@Query(nativeQuery=true, value=("""
			SELECT i.titulacio, pr.id_proces AS idProces, pr.nom_proces AS nomProces, pr.ambit, pr.curs_avaluat AS cursAvaluat, ti.id_tascai, 
			           ti.id_instancia AS idInstancia, ti.id_tasca AS idTasca, ti.version, ti.estat, ti.usuari_fet AS usuariFet, ti.data_fet AS dataFet, 
			           ti.evidencia FROM tasquesi ti 
			LEFT JOIN tasques ta ON ta.id_tasca = ti.id_tasca 
			LEFT JOIN instancies i ON i.id_instancia = ti.id_instancia 
			LEFT JOIN processos pr ON pr.id_proces = i.id_proces 
			WHERE (pr.nom_proces = ?1 OR pr.nom_proces IN(
				SELECT nom_proces_eq FROM processos_equivalents WHERE nom_proces = ?1 AND (estudi = ?4 OR estudi = 'GM') AND ambit = 'T'
				)) 
			AND i.titulacio = ?2 AND pr.ambit = 'T' 
			AND i.estat = 'F' AND ti.estat = 'E' AND ta.informe 
			UNION 
			SELECT i.titulacio, pr.id_proces AS idProces, pr.nom_proces AS nomProces, pr.ambit, pr.curs_avaluat AS cursAvaluat, ti.id_tascai, 
			       ti.id_instancia AS idInstancia, ti.id_tasca AS idTasca, ti.version, ti.estat, ti.usuari_fet AS usuariFet, ti.data_fet AS dataFet, 
			       ti.evidencia FROM tasquesi ti 
			LEFT JOIN tasques ta ON ta.id_tasca = ti.id_tasca 
			LEFT JOIN instancies i ON i.id_instancia = ti.id_instancia 
			LEFT JOIN processos pr ON pr.id_proces = i.id_proces 
			WHERE pr.nom_proces IN(SELECT nom_proces_eq FROM processos_equivalents WHERE nom_proces = ?1 AND (estudi = ?4 OR estudi = 'GM') AND ambit = 'C') 
			AND i.centre = ?3 AND pr.ambit = 'C' 
			AND i.estat = 'F' AND ti.estat = 'E' AND ta.informe 
			ORDER BY cursAvaluat DESC FETCH FIRST 1 ROW ONLY; """))
	public TascaInformeTransferDTO getLastByProcName(String proc, Integer tit, Integer centre, String estudi);	
	
	@Transactional
    @Modifying(flushAutomatically = true, clearAutomatically = true)
	@Query(value=("UPDATE tasquesi SET estat = null WHERE estat = 'A' AND id_instancia = ?1"), nativeQuery=true)
	public void deactivateAll(BigInteger idInstancia);
	
	@Transactional
    @Modifying(flushAutomatically = true, clearAutomatically = true)
	@Query(value=("DELETE FROM tasquesi WHERE id_instancia = ?1 AND id_tasca = ?2"), nativeQuery=true)
	public void removeAllVersions(BigInteger idInstancia, Integer idTasca);
	
	@Transactional
    @Modifying(flushAutomatically = true, clearAutomatically = true)
	@Query(value=("DELETE FROM tasquesi WHERE id_tascai = ?1"), nativeQuery=true)
	public void remove(BigInteger idInstanciaTasca);
	
}

