package es.uv.saic.web;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.time.Year;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import static java.util.Comparator.comparing;

import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;

import org.apache.commons.io.FilenameUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import es.uv.saic.domain.DummyDataTransfer;
import es.uv.saic.domain.EvidenciaIndicadorEnquesta;
import es.uv.saic.domain.Instancia;
import es.uv.saic.domain.InstanciaTasca;
import es.uv.saic.domain.InstanciaTascaTransfer;
import es.uv.saic.domain.InstanciaTascaVer;
import es.uv.saic.domain.InstanciaTransfer;
import es.uv.saic.domain.Organ;
import es.uv.saic.domain.Plantilla;
import es.uv.saic.domain.Proces;
import es.uv.saic.domain.Rol;
import es.uv.saic.domain.Tipus;
import es.uv.saic.domain.Usuari;
import es.uv.saic.dto.InstanciaTascaDTO;
import es.uv.saic.dto.PdfDTO;
import es.uv.saic.dto.ProcesDTO;
import es.uv.saic.dto.RolDTO;
import es.uv.saic.dto.TascaDTO;
import es.uv.saic.dto.TemplateDataDTO;
import es.uv.saic.feign.PlantillaClient;
import es.uv.saic.service.*;


@RestController
public class ProceduresController {

    private final ProcesService procesService;
	 
	@Autowired
	private UsuariService us;
	@Autowired
	private InstanciaService is;
	@Autowired
	private InstanciaTascaService its;
	@Autowired
	private InstanciaTascaVerService itsver;
	@Autowired
	private OrganService ors;
	@Autowired
    private ProcesService ps;
    @Autowired
    private TipusService tps;
    @Autowired
    private RolService rs;
    @Autowired
    private TascaService tas;
	@Autowired
	private EvidenciaIndicadorEnquestaService eies;
	@Autowired
	private PlantillaClient plc;
	@Value("${saic.data.filePath}")
	private String filePath;

    ProceduresController(ProcesService procesService) {
        this.procesService = procesService;
    }

	/*
	 * Load the list of active procedure instances for the logged-in user
	 * 
	 * @param model 
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param _new Optional parameter to indicate a new access
	 * @return The name of the view to render
	 */

	@GetMapping("/tipus/findAll")
	public List<Tipus> findAll() {
		return tps.findAll();
	}
	

	@PostMapping("/procedures")
	public HashMap<String, Object> getActiveInstances(@RequestParam(required = false) String _new, @RequestParam String usuari) {
		HashMap<String, Object> model = new HashMap<>();

		if(_new != null) {
			model.put("new_access", true);
		}
		
		Usuari u = us.findByUsername(usuari);
		List<InstanciaTransfer> plist = new ArrayList<InstanciaTransfer>();
		Instancia i;
		InstanciaTransfer it;
		InstanciaTasca itt;
		for(BigInteger p_id: this.us.getActiveInstancies(u)) {
			i = this.is.findByID(p_id);
			it = new InstanciaTransfer();
			it.setIdInstancia(i.getIdInstancia());
			it.setIdProces(i.getProces().getIdProces());
			it.setNomProces(i.getProces().getNomProces());
			it.setCursAvaluat(i.getProces().getCursAvaluat());
			it.setCursActivacio(i.getProces().getCursActivacio());
			it.setTitolCas(i.getProces().getTitolCas());
			it.setTitolVal(i.getProces().getTitolVal());
			it.setDescripcioCas(i.getProces().getDescripcioCas());
			it.setDescripcioVal(i.getProces().getDescripcioVal());
			it.setEstat(i.getEstat());
			if(i.getOrgan().getId().getTlugar().equals("C")) {
				Organ o = ors.findByID("T", i.getTitulacio());
				it.setTitulacioCas(o.getNomCas());
				it.setTitulacioVal(o.getNomVal());
				it.setCentreCas(i.getOrgan().getNomCas());
				it.setCentreVal(i.getOrgan().getNomVal());
			}
			else {
				it.setRuct(i.getOrgan().getRuct());
				it.setTitulacioCas(i.getOrgan().getNomCas());
				it.setTitulacioVal(i.getOrgan().getNomVal());
				it.setCentreCas(i.getOrgan().getOrgan().getNomCas());
				it.setCentreVal(i.getOrgan().getOrgan().getNomVal());
			}
			itt = its.findActiveByInstancia(i.getIdInstancia());
			it.setDataLimTascaActiva(itt.getTasca().getDataLim());
			it.setDataTascaActiva(itt.getData());
			it.setNomTascaActivaCas(itt.getTasca().getTitolCas());
			it.setNomTascaActivaVal(itt.getTasca().getTitolVal());
			it.setDescTascaActivaCas(itt.getTasca().getDescripcioCas());
			it.setDescTascaActivaVal(itt.getTasca().getDescripcioVal());
			it.setIdTascapActiva(itt.getTasca().getIdTascap());
			it.setTascaActivaExpired(itt.getTasca().isExpired());
			it.setTascaActivaAssignedToUser(its.isUserAuthorized(u, itt.getIdInstanciaTasca()));
			plist.add(it);
		}
		model.put("procedure_list", plist);
		return model;
	}
	
	/*
	 * Loads a procedure instance and its tasks
	 * 
	 * @param model 
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id Instancia ID Instance to load
	 * @return The name of the view to render
	 */
	@GetMapping("/procedure/{id}/{usuari}")
	public HashMap<String, Object> getInstance(@PathVariable BigInteger id, @PathVariable String usuari) {
		HashMap<String, Object> model = new HashMap<>();
		Usuari u = us.findByUsername(usuari);

		this.loadProcedure(model, u, id);
		return model;
	}
	

	/*
	 * Updates a task instance with evidence files (for specific task types)
	 * 
	 * @param model
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id Instancia ID Instance to load
	 * @param params Form parameters
	 * @param evidencias List of evidence files (if any)
	 * @return The number of files uploaded (as a String)
	 * @throws IllegalStateException
	 * @throws IOException
	 * @throws InterruptedException
	 */
	@PostMapping("/procedure/files/{id}")
	@ResponseBody 
	public HashMap<String, Object> updateInstanciaTascaEvidencia(@PathVariable BigInteger id, @RequestParam Map<String,String> params, 
			@RequestParam(required = true) List<MultipartFile> evidencias, @RequestParam String usuari) throws IllegalStateException, IOException {
		HashMap<String, Object> model = new HashMap<>();
		Usuari u = us.findByUsername(usuari);
		
		InstanciaTasca it = its.findById(new BigInteger(params.get("taskid")));
		
		/* Tipos de tarea permitidas */
		final Set<Integer> suitable = Set.of(1, 12, 14);
		
		boolean newTask = (suitable.contains(it.getTasca().getTipus().getTipus())) && it.getEstat().equals("E") && 
						   (u.isAdmin() || u.isGranted());
		
		if(suitable.contains(it.getTasca().getTipus().getTipus())) {   // Evidencia iterable
			String fileName = "";
			
			if(evidencias.size() > 1) {
				fileName = (newTask ? it.getIdInstanciaTasca().add(new BigInteger("1")).toString() : it.getIdInstanciaTasca().toString()) + ".zip";
				try (ZipOutputStream zipOut = new ZipOutputStream(new FileOutputStream(filePath+fileName))) {
				    for(MultipartFile f : evidencias) {
				    	File tempFile = File.createTempFile("saic", "temp");
				    	tempFile.deleteOnExit();
				    	f.transferTo(tempFile);
				        zipOut.putNextEntry(new ZipEntry(f.getOriginalFilename()));
				        Files.copy(Paths.get(tempFile.getAbsolutePath()), zipOut);
				    }
				}		
			}
			else if(evidencias.size() == 1){
				MultipartFile evidencia = evidencias.get(0);
				fileName = (newTask ? it.getIdInstanciaTasca().add(new BigInteger("1")).toString() : it.getIdInstanciaTasca().toString()) + "." +
						FilenameUtils.getExtension(evidencia.getOriginalFilename());
				evidencia.transferTo(new File(filePath+fileName));
			}
			else {
				model.put("ammount", "0");
				return model;
			}
			
			if(newTask){
				InstanciaTasca itNew = new InstanciaTasca();
				itNew.setUsuari(u);
				itNew.setDataFet(new Date(System.currentTimeMillis()));
				itNew.setData(new Date(System.currentTimeMillis()));
				itNew.setEstat("E");
				itNew.setEvidencia(fileName);
				itNew.setInstancia(it.getInstancia());
				itNew.setTasca(it.getTasca());
				itNew.setVersion(it.getVersion()+1);
				itNew.setIdInstanciaTasca(it.getIdInstanciaTasca().add(new BigInteger("1")));
				its.save(itNew);
			}
			else {
				it.setEvidencia(fileName);
				it.setEstat("E");
				this.saveChanges(u, it);
			}	
		}
		model.put("ammount", Integer.toString(evidencias.size()));
		return model; 
	}
	
	/*
	 * Updates a task instance
	 * 
	 * @param model 
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id Instancia ID Instance to load
	 * @param params Form parameters
	 * @param evidencias List of evidence files (if any)
	 * @return The name of the view to render
	 */
	@PostMapping("/procedure/{id}")
	public HashMap<String, Object> updateInstanciaTasca(@PathVariable BigInteger id, @RequestParam Map<String,String> params, 
			@RequestParam(required = false) List<MultipartFile> evidencias, @RequestParam String usuari) throws IllegalStateException, IOException, InterruptedException {
		HashMap<String, Object> model = new HashMap<>();
		Usuari u = us.findByUsername(usuari);
	
		// Update task instance 
		InstanciaTasca it = its.findById(new BigInteger(params.get("taskid")));
		if(it.getTasca().getTipus().getTipus() == 4) { // Avanzar
			it.setEstat("F");
		}
		else if(it.getTasca().getTipus().getTipus() == 2) { // SI/NO
			if(params.get("response").equals("0")) {
				it.setEstat("N");
			}
			else {
				it.setEstat("S");
			}
		}
		else if(it.getTasca().getTipus().getTipus() == 11 || it.getTasca().getTipus().getTipus() == 15) { // Evidencias online
			it.setText(params.get("evidencia_text"));
			PdfDTO pdf = new PdfDTO(params.get("evidencia_text"), it.getIdInstanciaTasca());
			it.setEvidencia(this.plc.savePDF(pdf));
			it.setEstat("E");
		}

		this.saveChanges(u, it);
		this.loadProcedure(model, u, id);
		return model; 
	}
	
	/*
	 * Saves changes to a task instance
	 * 
	 * @param model 
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param it InstanciaTasca to save
	 */
	public void saveChanges(Usuari u, InstanciaTasca it) {	
		this.its.saveChanges(u, it);
	}
	

	/*
	 * Saves a draft of a task instance (for specific task types)
	 * 
	 * @param model
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id Instancia ID Instance to load
	 * @param text Text content of the draft
	 * @param manual Whether the save was manually triggered by the user
	 * @return The timestamp of the save operation formatted as a String
	 */
	@PostMapping("/procedure/save/{id}")
	@ResponseBody
	public HashMap<String, Object> saveDraft(@PathVariable BigInteger id, @RequestParam String text, 
							@RequestParam boolean manual, @RequestParam String usuari) {
		HashMap<String, Object> model = new HashMap<>();
		Usuari u = us.findByUsername(usuari);

		InstanciaTasca it = its.findById(id);
		it.setText(text);
		it.setUsuari(u);
		it.setDataMod(new Date(System.currentTimeMillis()));
		its.save(it);
		if(manual){
			List<InstanciaTascaVer> itvs = this.itsver.findByIdInstanciaTasca(id);
			InstanciaTascaVer itv = new InstanciaTascaVer(id, it.getUsuari().getUsuari(), it.getText(), new Timestamp(it.getDataMod().getTime()));
			if(itvs != null){
				if(itvs.size() == 10){
					this.itsver.delete(itvs.get(itvs.size()-1));
				}
			}
			this.itsver.save(itv);
		}
		
		model.put("date", String.format("%1$td/%1$tm/%1$tY %1$tH:%1$tM:%1$tS", it.getDataMod()));
		return model;
	}
	
	/*
	 * Loads a procedure instance and its tasks into the model
	 * @param model
	 * @param auth Authentication
	 * @param id Instancia ID Instance to load
	 * @return The name of the view to render
	 */
	public void loadProcedure(HashMap<String, Object> model, Usuari usuari, BigInteger id) {
		Instancia i = is.findByID(id);
		InstanciaTransfer inst = new InstanciaTransfer();
		inst.setIdInstancia(i.getIdInstancia());
		inst.setIdProces(i.getProces().getIdProces());
		inst.setNomProces(i.getProces().getNomProces());
		inst.setCursAvaluat(i.getProces().getCursAvaluat());
		inst.setCursActivacio(i.getProces().getCursActivacio());
		inst.setTitolCas(i.getProces().getTitolCas());
		inst.setTitolVal(i.getProces().getTitolVal());
		inst.setDescripcioCas(i.getProces().getDescripcioCas());
		inst.setDescripcioVal(i.getProces().getDescripcioVal());
		inst.setEstat(i.getEstat());
		if(i.getOrgan().getId().getTlugar().equals("C")) {
			Organ o = ors.findByID("T", i.getTitulacio());
			inst.setTitulacioCas(o.getNomCas());
			inst.setTitulacioVal(o.getNomVal());
			inst.setCentreCas(i.getOrgan().getNomCas());
			inst.setCentreVal(i.getOrgan().getNomVal());
		}
		else {
			inst.setTitulacioCas(i.getOrgan().getNomCas());
			inst.setTitulacioVal(i.getOrgan().getNomVal());
			inst.setCentreCas(i.getOrgan().getOrgan().getNomCas());
			inst.setCentreVal(i.getOrgan().getOrgan().getNomVal());
			inst.setRuct(i.getOrgan().getRuct());
		}
		model.put("instance", inst);
		
		List<InstanciaTascaTransfer> tasks = new ArrayList<InstanciaTascaTransfer>();
		Boolean active;
		for(InstanciaTasca it : its.findByInstancia(i.getIdInstancia())) {
			active = false;
			InstanciaTascaTransfer itt = new InstanciaTascaTransfer();
			itt.setIdInstanciaTasca(it.getIdInstanciaTasca());
			itt.setIdTasca(it.getTasca().getIdTasca());
			itt.setIdProces(it.getTasca().getProces().getIdProces());
			itt.setTitolCas(it.getTasca().getTitolCas());
			itt.setTitolVal(it.getTasca().getTitolVal());
			itt.setDescripcioCas(it.getTasca().getDescripcioCas());
			itt.setDescripcioVal(it.getTasca().getDescripcioVal());
			itt.setTipus(it.getTasca().getTipus().getTipus());
			itt.setDataLim(formatDate(it.getTasca().getDataLim()));
			itt.setEstat(it.getEstat());
			itt.setIsExpired(it.getTasca().isExpired());
			itt.setIdTascap(it.getTasca().getIdTascap());
			itt.setDescripcioRolCas(it.getTasca().getRol().getDescripcioCas());
			itt.setDescripcioRolVal(it.getTasca().getRol().getDescripcioVal());
			itt.setDataFet(formatDate(it.getDataFet()));
			itt.setEstatInstancia(it.getInstancia().getEstat());
			itt.setOpcions(it.getTasca().getOpcions());
			itt.setDataMod(formatDate(it.getDataMod()));
			
			if(itt.getEstat() != null) {
				if(itt.getEstat().equals("A")) {
					active = true;
				}
			}
			
			if(it.getTasca().getTipus().getTipus() == 11 || it.getTasca().getTipus().getTipus() == 15) {
				Plantilla p = plc.findByID(Integer.parseInt(it.getTasca().getCodiEvidencia()));
				Plantilla p2 = null;
				
				if(i.getTitulacio() > 0) {
					if(!p.getAmbit().equals(i.getOrgan().getTambit())) {
						p2 = plc.findByVersioCodiAmbit(p.getVersio(), p.getCodi(), i.getOrgan().getTambit());
					}
				}			
				
				if(p2 != null) {
					p = p2;
				}
						
				itt.setCodiEvidencia(p.getCodi());
				itt.setNomEvidenciaCas(p.getNomCas());
				itt.setNomEvidenciaVal(p.getNomVal());
				/* Comprobar estado evidencia, si vacío inyectar contenido de plantilla asociada */
				if(it.getText() == null && active) {
					InstanciaTascaDTO itDTO = new InstanciaTascaDTO(it);
					TemplateDataDTO td = new TemplateDataDTO(itDTO, p.getText());
					itt.setText(plc.addTemplateData(td));
				}
				else if(active){
					itt.setText(it.getText());
				}
			}
			else {
				itt.setCodiEvidencia(it.getTasca().getCodiEvidencia());
				itt.setNomEvidenciaCas(it.getTasca().getNomEvidenciaCas());
				itt.setNomEvidenciaVal(it.getTasca().getNomEvidenciaVal());
				itt.setEvidencia(it.getEvidencia());
			}
			
			if(it.getUsuari() != null) {
				itt.setUsuariFet(it.getUsuari().getNom() + " " + it.getUsuari().getCognoms());
			}
			else {
				itt.setUsuariFet("");
			}			
			itt.setAssignedToUser(its.isUserAuthorized(usuari, itt.getIdInstanciaTasca()));
			itt.setOldEvidences(its.findOlderByProces(it.getInstancia().getCentre(), it.getInstancia().getTitulacio(), it.getInstancia().getProces().getNomProces(), i.getProces().getCursActivacio()));
			itt.setVersions(its.findOlderVersions(it.getInstancia().getIdInstancia(), it.getTasca().getIdTasca(), it.getVersion()));
			tasks.add(itt);
		}
		model.put("tasks", tasks);
		model.put("flow", this.getFlowDiagram(i.getProces()));
	}

	private String formatDate(Date date) {
		if (date == null) return "";
		SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy");
		return formatter.format(date);
	}


	/*
	 * Get all drafts for a given task instance
	 * @param model
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id InstanciaTasca ID to load drafts for
	 * @return The name of the view to render
	 */
	@GetMapping("/procedure/drafts/{id}")
	public HashMap<String, Object> getDrafts(@PathVariable BigInteger id) {
		HashMap<String, Object> model = new HashMap<>();
		List<InstanciaTascaVer> itvs = this.itsver.findByIdInstanciaTasca(id);
		model.put("versions", itvs);
		model.put("idInstanciaTasca", id);
		return model;
	}

	/*
	 * Get a specific draft for a given task instance
	 * @param model
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id InstanciaTasca ID to load drafts for
	 * @param dataMod Timestamp of the draft to load
	 * @return The InstanciaTascaVer object representing the draft
	 */
	@GetMapping("/procedure/draft/{id}")
	@ResponseBody
	public InstanciaTascaVer getDraft(@PathVariable BigInteger id, @RequestParam Timestamp dataMod) {
		return this.itsver.findById(id, dataMod);
	}

	/*
	 * Restore a specific draft for a given task instance
	 * @param model
	 * @param auth Authentication
	 * @param session HttpSession
	 * @param id InstanciaTasca ID to restore draft for
	 * @param dataMod Timestamp of the draft to restore
	 * @return "1" if successful, "0" otherwise
	 */
	@PostMapping("/procedure/draft/{id}")
	@ResponseBody
	public String restoreDraft(@PathVariable BigInteger id, @RequestParam Timestamp dataMod) {
		try{
			InstanciaTascaVer itv = this.itsver.findById(id, dataMod);
			InstanciaTasca it = this.its.findById(id);
			it.setText(itv.getText());
			this.its.save(it);
		}
		catch(Exception e){
			return "0";
		}

		return "1";
	}

	/*
	 * Generate a flow diagram for a given process
	 * @param proces The process to generate the flow diagram for
	 * @return A String containing the flow diagram
	 */
	private String getFlowDiagram(Proces proces){
		List<String> flow = this.procesService.getFlowDiagram(proces);
		return "graph TD \n" + String.join("\n", flow);
	}

    @PostMapping("/proces/{id}")
    public ResponseEntity<?> findById(@PathVariable Integer id) {
        try {
            Proces proces = ps.findByID(id);
            ProcesDTO procesDTO = new ProcesDTO(proces);

            return (procesDTO != null) ? ResponseEntity.ok(procesDTO) : ResponseEntity.badRequest().body("El proces con id " + id + " esta vacio");
        } catch (Exception e) {
             e.printStackTrace();
            return ResponseEntity.badRequest().body("Error al obtener el proces por el id:" +  e.getMessage());
        }
    }
    
    @GetMapping("/proces/getAll")
    public ResponseEntity<?> getAll() {
        try {
            List<Proces> proces = ps.getAll();
            List<ProcesDTO> procesDTOList = new ArrayList<>();
            
            for(Proces pro: proces) {
                procesDTOList.add(new ProcesDTO(pro));
            }

            return ResponseEntity.ok(procesDTOList);
        } catch(Exception e) {
            return ResponseEntity.badRequest().body("Error al obtener los centros");
        }
    }
    
    @PostMapping("/ajax/search/years")
	public HashMap<String, Object> getYearsByCenterTitulation(
			@RequestParam(name="centers[]", required=false) List<Integer> centres,
			@RequestParam("titulations[]") List<Integer> titulacions, @RequestParam String usuari) throws IOException {
            
            HashMap<String, Object> model = new HashMap<>();
            Usuari u = us.findByUsername(usuari);

			List<DummyDataTransfer> supervisable_years = new ArrayList<DummyDataTransfer>();
			if(centres == null) { centres = us.getSupervisableCentres(u); }
			for(Integer c : ps.getSupervisableCursos(centres, titulacions)) {
				DummyDataTransfer d = new DummyDataTransfer();
				d.setValue(c);
				d.setText(Integer.toString(c-1) + " - " + Integer.toString(c));
				supervisable_years.add(d);
			}

			Collections.sort(supervisable_years, (a, b) -> {
				return a.getText().compareTo(b.getText());
			});

			model.put("sup_years", supervisable_years);
		return model;
	}

    @PostMapping("/ajax/search/procedures")
	public HashMap<String, Object> getProceduresByCenterTitulationYear(
            @RequestParam(name="centers[]", required=false) List<Integer> centres,
			@RequestParam("years[]") List<Integer> cursos,
			@RequestParam("titulations[]") List<Integer> titulacions,
            @RequestParam String usuari) throws IOException {	
		
        HashMap<String, Object> model = new HashMap<>();
        Usuari u = us.findByUsername(usuari);

        List<DummyDataTransfer> supervisable_procedures = new ArrayList<DummyDataTransfer>();
		if(centres == null) { centres = us.getSupervisableCentres(u); }
		for(Integer p_id : ps.getSupervisableProcedures(u, cursos, centres, titulacions)) {
			DummyDataTransfer d = new DummyDataTransfer();
			Proces p = ps.findByID(p_id);
			d.setText(p.getNomProces());
			d.setText2(p.getNomProces() + " " + p.getTitolCas());
			d.setText3(p.getNomProces() + " " + p.getTitolVal());
			supervisable_procedures.add(d);
		}
		
		Set<String> set = new HashSet<>(supervisable_procedures.size());
		supervisable_procedures.removeIf(p -> !set.add(p.getText()));
		Collections.sort(supervisable_procedures, comparing(DummyDataTransfer::getText));
		model.put("sup_procs", supervisable_procedures);

		return model;
	}

    @PostMapping("/ajax/find/procedure")
	public HashMap<String, Object> findProcedure(@RequestParam("procedure") String idProces, 
			@RequestParam("action") String action) throws IOException {	
		
		HashMap<String, Object> model = new HashMap<>();
		Proces p = new Proces();
		model.put("action", action);
		List<Tipus> tipus = tps.findAll();
		List<Plantilla> templates = plc.findAll();
		model.put("tipus", tipus);
		model.put("templates", templates);
		System.out.println(idProces);
		
		if(!idProces.equals("0") && (action.equals("duplicate") || action.equals("edit"))) {
			p = ps.findByID(Integer.parseInt(idProces));
			if(action.equals("duplicate")) {
				p.setVersio(Integer.toString(Integer.parseInt(p.getVersio())+1));
				p.setIdProces(p.getIdProces()+1);
				p.setCursActivacio(Year.now().getValue());
				p.setCursAvaluat(null);
			}
			model.put("tasks", this.tas.findByProces(Integer.parseInt(idProces)).stream().map(TascaDTO::new).toList());
			ProcesDTO pDto = new ProcesDTO(p);
			model.put("procedure", pDto);
			List<Rol> roles = rs.findAssignables();
			model.put("roles", roles.stream().map(RolDTO::new).toList());
            return model;
		}
		else if(!idProces.equals("0") && action.equals("remove")) {
			p = ps.findByID(Integer.parseInt(idProces));
			ProcesDTO pDto = new ProcesDTO(p);
			model.put("procedure", pDto);
			return model;
		}
		else {
			ProcesDTO pDto = new ProcesDTO(p);
			model.put("procedure", pDto);
			List<Rol> roles = rs.findAssignables();
			model.put("roles", roles);
			return model;
		}	
	}

	@PostMapping("/ajax/template/form")
	public HashMap<String, Object> formTemplate(@RequestParam("id") Integer idPlantilla,
			@RequestParam("action") String action) throws IOException {	
		
		HashMap<String, Object> model = new HashMap<>();

		if(action.equals("new")) {
			Plantilla p = new Plantilla();
				model.put("editable", true);
			model.put("template", p);
			model.put("redirect", true);
			return model;
		}
		else if(action.equals("edit")) {
			Plantilla p = plc.findByID(idPlantilla);
			model.put("editable", false);
			model.put("template", p);
			model.put("redirect", true);
			return model;
		}
		else if(action.equals("duplicate")) {
			Plantilla p = plc.findByID(idPlantilla);
			p.setVersio(p.getVersio()+1);
			model.put("editable", true);
			model.put("template", p);
			model.put("redirect", true);
			return model;
		}
		model.put("redirect", false);
		return model;
	}

	@GetMapping("/find/proces/{idProces}")
	public Proces findProcesByID(@PathVariable Integer idProces) {
		return ps.findByID(idProces);
	}
	
	@GetMapping("/getByProcesEvidencia")
	public List<EvidenciaIndicadorEnquesta> getByProcesEvidencia(@RequestParam String nomProces, @RequestParam String evidencia) {
		return eies.getByProcesEvidencia(nomProces, evidencia);
	}
	
}