package es.uv.saic.web;

import java.io.IOException;
import java.math.BigInteger;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Optional;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.DeleteMapping;
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 es.uv.saic.domain.Calendari;
import es.uv.saic.domain.Email;
import es.uv.saic.domain.InstanciaTasca;
import es.uv.saic.domain.Organ;
import es.uv.saic.domain.Proces;
import es.uv.saic.domain.Usuari;
import es.uv.saic.service.CalendariService;
import es.uv.saic.service.EmailService;
import es.uv.saic.service.InstanciaService;
import es.uv.saic.service.InstanciaTascaService;
import es.uv.saic.service.OrganService;
import es.uv.saic.service.ProcesService;
import es.uv.saic.service.UsuariService;

@RestController
public class CalendarController {
    @Autowired
	private OrganService os;
	@Autowired
	private UsuariService us;
	@Autowired
	private ProcesService ps;
	@Autowired
	private CalendariService cs;
	@Autowired
	private InstanciaService is;
	@Autowired
	private InstanciaTascaService its;
	@Autowired
	private EmailService es;
	
	// POST para añadir un evento al calendario
	@ResponseBody
	@PostMapping("/ajax/calendar")
	public Calendari calendarAddEvent(@RequestParam("idProces") Integer idProces, 
			@RequestParam("titulacions") List<String> titulacions, @RequestParam("centres") List<String> centres, 
			@RequestParam("data") String data, @RequestParam("instancia") Optional<Integer> instancia) throws IOException, ParseException {	
		
		Date d = new SimpleDateFormat("dd/MM/yyyy").parse(data);
		String dstr = new SimpleDateFormat("yyyy-MM-dd").format(d);
		Proces p = this.ps.findByID(idProces);
		Calendari c = new Calendari();
		c.setIdProces(p.getIdProces());
		c.setData(d);
		c.setDataStr(dstr);
		c.setTitolCas(p.getNomProces() + " " + p.getTitolCas());
		c.setTitolVal(p.getNomProces() + " " + p.getTitolVal());
		c.setAmbit(p.getAmbit());
		c.setTipus(1);
		c.setColor(p.getAmbit().equals("C")  ? "aquamarine" : "dodgerblue");
		c.setStatus("P");
		if(instancia.isPresent()) {
			Calendari cold = cs.findById(instancia.get());
			c.setCentres(cold.getCentres());
			c.setTitulacions(cold.getTitulacions());
		}
		else {
			c.setCentres(centres.toString());
			c.setTitulacions(titulacions.toString());
		}
		
		c = cs.save(c);
		
		return c;
	}
	
	// POST que actualiza el evento ddel calendario
	@ResponseBody
	@PostMapping("/ajax/calendar/{id}")
	public Calendari calendarAddEvent(@PathVariable("id") Integer id, 
			@RequestParam("idProces") Integer idProces, @RequestParam("titulacions") List<String> titulacions, 
			@RequestParam("centres") List<String> centres, @RequestParam("data") String data) throws IOException, ParseException {	
		
		Calendari c = cs.findById(id);
		Date d = new SimpleDateFormat("dd/MM/yyyy").parse(data);
		String dstr = new SimpleDateFormat("yyyy-MM-dd").format(d);
		Proces p = this.ps.findByID(idProces);
		c.setIdProces(p.getIdProces());
		c.setData(d);
		c.setDataStr(dstr);
		c.setCentres(centres.toString());
		c.setTitulacions(titulacions.toString());
		c.setTitolCas(p.getNomProces() + " " + p.getTitolCas());
		c.setTitolVal(p.getNomProces() + " " + p.getTitolVal());
		c.setAmbit(p.getAmbit());
		c.setColor(p.getAmbit().equals("C") ? "aquamarine" : "dodgerblue");
		c.setStatus("P");
		
		c = cs.save(c);
		
		return c;
	}
	
	// GET que recoge todos los eventos del calendario
	@ResponseBody
	@GetMapping("/ajax/calendar")
	public List<Calendari> calendarGetEvents() throws IOException, ParseException {	
		return cs.getAll();
	}
	
	// DELETE que elimina un evento del calendario
	@ResponseBody
	@DeleteMapping("/ajax/calendar")
	public Integer calendarDeleteEvent(@RequestParam("id") Integer id) throws IOException, ParseException {	
		Calendari c = this.cs.findById(id);
		this.cs.delete(c);
		return id;
	}
	

	// POST para instanciar un proceso desde el calendario
	@ResponseBody
	@PostMapping("/ajax/instantiate")
	public List<String> instantiate(@RequestParam("id") Integer id,
			@RequestParam("idProces") Integer idProces, @RequestParam("centres") List<Integer> centres,
			@RequestParam("titulacions") List<Integer> titulacions, @RequestParam String usuari) throws IOException, ParseException {	
		
        Usuari u = us.findByUsername(usuari);
        if(!u.isAdmin()) {
			return null;
		}
		
		Calendari cal = cs.findById(id);
		if(!cal.getIdProces().equals(idProces) || !cal.getCentres().equals(centres.toString()) 
				|| !cal.getTitulacions().equals(titulacions.toString())) {
			cal.setCentres(centres.toString());
			cal.setTitulacions(titulacions.toString());
			cal.setIdProces(idProces);
			cs.save(cal);
		}
		
		List<String> log = new ArrayList<String>();
		boolean hasErrors = false;
		
		Proces pr = ps.findByID(idProces);
		
		if(pr.getAmbit().equals("U")) {  // ambit == universitat (U)
			for(Integer idTitulacio : titulacions) {
				BigInteger idInstancia = is.instantiateU(idProces, idTitulacio);
				if(!idInstancia.equals(new BigInteger("0"))) {
					log.add("[OK] "+idInstancia.toString()+" - "+groupedTitToText(idTitulacio));
					InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
					for(Usuari usr : us.getInstanceAsignedUsers(idInstancia)) {
						Email email = new Email();
						email.setUsusari(usr);
						email.setInstanciaTasca(activa);
						es.addEmail(email);
					}
				}
				else {
					log.add("[ERROR] "+groupedTitToText(idTitulacio));
					hasErrors = true;
				}		
			}
		}
		else if(pr.getAmbit().equals("C")) { // ambit == centre (C)
			for(Integer idCentre : centres) {
				Organ c = os.findByID("C", idCentre);
				for(Integer idTitulacio : titulacions) {
					BigInteger idInstancia = is.instantiateC(idProces, c.getId().getLugar(), idTitulacio);
					if(!idInstancia.equals(new BigInteger("0"))) {
						log.add("[OK] "+idInstancia.toString()+" - "+c.getNomCas() + " -> " + groupedTitToText(idTitulacio));
						InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
						for(Usuari usr : us.getInstanceAsignedUsers(idInstancia)) {
							Email email = new Email();
							email.setUsusari(usr);
							email.setInstanciaTasca(activa);
							es.addEmail(email);
						}
					}
					else {
						hasErrors = true;
						log.add("[ERROR] "+c.getNomCas() + " -> " + groupedTitToText(idTitulacio));
					}
				}
			}
		}
		else if(pr.getAmbit().equals("T")) { // ambit == titulacio (T)
			for(Integer idTitulacio : titulacions) {
				Organ t = os.findByID("T", idTitulacio);
				BigInteger idInstancia = is.instantiateT(idProces, t.getId().getLugar());
				if(!idInstancia.equals(new BigInteger("0"))) {
					log.add("[OK] "+idInstancia.toString()+" - "+t.getNomCas());
					InstanciaTasca activa = its.findActiveByInstancia(idInstancia);
					for(Usuari usr : us.getInstanceAsignedUsers(idInstancia)) {
						Email email = new Email();
						email.setUsusari(usr);
						email.setInstanciaTasca(activa);
						es.addEmail(email);
					}
				}
				else {
					hasErrors = true;
					log.add("[ERROR] "+idInstancia.toString()+" - "+t.getNomCas());
				}
			}
		}
		
		if(hasErrors) {
			cal.setStatus("E");
			cal.setColor("indianred");
			cal.setData(new Date(System.currentTimeMillis()));
			cs.save(cal);
		}
		else {
			cal.setStatus("F");
			cal.setColor("lightgreen");
			cal.setData(new Date(System.currentTimeMillis()));
			cs.save(cal);
		}
		
		return log;
	}
	
	private String groupedTitToText(Integer t) {
		if(t == 1) {
			return "Grados";
		}
		else if(t == 2) {
			return "Masters";
		}
		else if(t == 3) {
			return "Doctorados";
		}
		else {
			return "Todas Titulaciones";
		}
	}
}
