package es.uv.saic.web;

import java.io.IOException;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import jakarta.mail.MessagingException;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.security.access.annotation.Secured;
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.multipart.MultipartFile;

import es.uv.saic.domain.Datasource;
import es.uv.saic.domain.IndicadorEnquesta;
import es.uv.saic.domain.Usuari;
import es.uv.saic.dto.EnquestaDTO;
import es.uv.saic.dto.ImportDTO;
import es.uv.saic.dto.IndicadorEnquestaTmpDup;
import es.uv.saic.dto.TablaDTO;
import es.uv.saic.feign.CoreClient;
import es.uv.saic.feign.DataClient;

@Controller
public class DataController {

	@Autowired
	private CoreClient cc;
	
	@Autowired
	private DataClient dc;
	
	// GET que carga la interfaz relacionada con toda la importación de datos
	@GetMapping("/data/import")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	public String renderImport(Model model, Authentication auth) {
		List<Datasource> sources = dc.renderImport();
		for(Datasource d : sources){
			d.setConn(null);
		}
		model.addAttribute("sources", sources);
		return "dataImport";
	}
	
	// POST encargado de importar los datos que han sido adjuntados
	@PostMapping("/data/import")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public String uploadFile(Model model, Authentication auth, MultipartFile file, @RequestParam String enquesta, @RequestParam String ambit,
							@RequestParam String estudi, @RequestParam String clau, @RequestParam String tipus, @RequestParam List<String> ignoredColumns,
							@RequestParam(required = false) String vista, @RequestParam(required = false) String delim, 
							@RequestParam(required = false) Integer curs, @RequestParam(required = false) Integer dstCurs,
							@RequestParam(required = false) Integer dbOrigen) throws IOException, MessagingException, ClassNotFoundException, SQLException { 
		String locale = LocaleContextHolder.getLocale().getLanguage();
		ImportDTO importDto = new ImportDTO(file, tipus, (Usuari)auth.getPrincipal(), enquesta, ambit, estudi, locale, delim, clau, ignoredColumns, dbOrigen, vista, curs, dstCurs);
		
		try {
			return dc.uploadFile(importDto);
		} catch (Exception e) {
			System.err.println("Failed to find Document: " + e.getMessage());
		}
		
		return "Failed to import document";
		
	}

	// POST encargado de eliminar unos datos concretos
	@PostMapping("/data/delete")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public String delete(Model model, Authentication auth, @RequestParam String enquesta,
			@RequestParam Integer curs, @RequestParam String ambit, @RequestParam String estudi) throws IOException {  

		String retval = "";
		EnquestaDTO enquestaDTO = new EnquestaDTO(enquesta, curs, ambit, estudi); 
	
		Integer r = cc.deleteByEnquestaCursAmbitEstudi(enquestaDTO);
		String locale = LocaleContextHolder.getLocale().getLanguage();
		retval = locale.equals("es") ? "[INFO] Se han eliminado "+r+" registros" : "[INFO] S'han esborrat "+r+" registres";			

        return retval;
	}
	
	// POST encargado de mostrar los datos por pantalla
	@PostMapping("/data/show")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public List<IndicadorEnquesta> show(Model model, Authentication auth, @RequestParam String enquesta,
			@RequestParam Integer curs, @RequestParam String ambit, @RequestParam String estudi) throws IOException {    
		EnquestaDTO enquestaDTO = new EnquestaDTO(enquesta, curs, ambit, estudi); 
			
		return cc.findByEnquestaCursAmbitEstudi(enquestaDTO);
	}
	
	// GET para mostrar el formulario de busqueda de datos
	@GetMapping("/data/current")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	public String current(Model model, Authentication auth) throws IOException {
		model.addAttribute("data", cc.getTitulacionsWithCentre());			
		return "dataCurrent";
	}
	
	//GET para cargar el apartado de coonsolidate
	@GetMapping("/data/consolidate")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	public String consolidate(Model model, Authentication auth) throws IOException {    
		return "dataConsolidate";
	}
	
	// POST para comprobar si existen problemas con los datos, si estan duplicados o su integridad
	@PostMapping("/data/check/{type}")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public List<IndicadorEnquestaTmpDup> check(Model model, Authentication auth, 
			@RequestParam String enquesta, @PathVariable Integer type) throws IOException {   
		return dc.check(enquesta, type);
	}

	// POST que soluciona problemas de integridad que puedan tener los datos
	@PostMapping("/data/fix/integrity/{deleteFrom}")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public Integer fixIntegrityIssues(Model model, Authentication auth, 
			@RequestParam String enquesta, @PathVariable String deleteFrom) throws IOException {   
		
		if(deleteFrom.equals("current")) {
			return cc.deleteFromCurrent(enquesta);
		}
		else if(deleteFrom.equals("new")) {
			return cc.deleteFromPending(enquesta);
		}

		return 0;
	}

	// POST que soluciona problemas de duplicados que puedan tener los datos
	@PostMapping("/data/fix/duplication")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public Integer fixDuplicatesIssues(Model model, Authentication auth, @RequestParam String enquesta) throws IOException {   
		return cc.deleteDuplicates(enquesta);
	}
	
	// POST que consolida los datos pasadas por la encuesta
	@PostMapping("/data/consolidate")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public Integer consolidate(Model model, Authentication auth, @RequestParam String enquesta) throws IOException {    
		return dc.countByEnquesta(enquesta);
	}
	
	// POST que comprueba los datos a partir de la encuesta
	@PostMapping("/data/count")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public Integer countByEnquesta(Model model, Authentication auth, @RequestParam String enquesta) throws IOException {    
		return dc.countByEnquesta(enquesta);
	}

	// POST para mostrar los datos en columnas
	@PostMapping("/data/view/columns")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public List<String> listTableColumns(Model model, Authentication auth, @RequestParam Integer dbOrigen, @RequestParam String vista) {    
		String locale = LocaleContextHolder.getLocale().getLanguage();
		List<String> list = null;

		try {
			TablaDTO tablaDTO = new TablaDTO(dbOrigen, vista, locale);
			return dc.listTableColumns(tablaDTO);	
				
		} catch (Exception e) {
			System.err.println("Failed to load table: " + e.getMessage());
		}

		return list;
	}

	// GET que muestra los datos de un curso que se ha elegido
	@GetMapping("/data/current/show/{ruct}/{curs}")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public List<IndicadorEnquesta> show(Model model, Authentication auth, @PathVariable Integer ruct, 
			@PathVariable Integer curs) throws IOException { 
        return cc.getAllIndsByRuct(ruct, curs);
	}
	
	// POST que muestra los datos del curso actual
	@PostMapping("/data/current/show")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public List<IndicadorEnquesta> currentShow(Model model, Authentication auth, @RequestParam String enquesta,
			@RequestParam Integer curs, @RequestParam String ambit, @RequestParam String estudi,
			@RequestParam Integer centre, @RequestParam Integer titulacio) throws IOException {   
		
		List<IndicadorEnquesta> inds = new ArrayList<IndicadorEnquesta>();
		EnquestaDTO enquestaDTO = new EnquestaDTO(enquesta, curs, ambit, estudi, centre, titulacio);
		
		if(ambit.equals("U")) {
			inds = cc.findByEnquestaCursAmbitEstudi(enquestaDTO);
		}
		else if(ambit.equals("C")) {
			inds = cc.findByEnquestaCursAmbitEstudiCentre(enquestaDTO);
		}
		if(ambit.equals("T")) {
			inds = cc.findByEnquestaCursAmbitEstudiCentreTitulacio(enquestaDTO);
		}

        return inds;
	}

	@GetMapping("/data/sources")
	@Secured({"ROLE_ADMIN", "ROLE_TESTER"})
	@ResponseBody
	public List<Datasource> getDatasources(Model model, Authentication auth) throws IOException {  
    	return dc.getDatasources();
	}
}
