package es.uv.saic.web;

import java.io.IOException;
import java.math.BigInteger;
import java.sql.Timestamp;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
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.InstanciaTascaVer;
import es.uv.saic.domain.Usuari;
import es.uv.saic.feign.ProceduresClient;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.servlet.http.HttpSession;


@Controller
public class ProceduresController {

	@Autowired
	private ProceduresClient pc;
	@Value("${saic.data.filePath}")
	private String filePath;
		
	/* Redirect root to /procedures */
	@GetMapping("/")
	public void getRoot(Model model, Authentication auth, HttpSession session, HttpServletResponse response) throws IOException {
		response.sendRedirect("/procedures");
	}
	
	/*
	 * 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("/procedures")
	public String getActiveInstances(Model model, Authentication auth, HttpSession session, @RequestParam(required = false) String _new) {
		
		HashMap<String, Object> response =
                pc.getActiveInstances( _new, ((Usuari) auth.getPrincipal()).getUsuari());

        if (response != null && response.get("redirect") != null) {
			model.addAllAttributes(response);
			session.setAttribute("location", model.getAttribute("location"));
            return response.get("redirect").toString();
        }

		return "401";
	}
	
	/*
	 * 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}")
	public String getInstance(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id) {
		
		HashMap<String, Object> response =
                pc.getInstance(session.getAttribute("location").toString(), id, ((Usuari) auth).getUsuari());
        if (response != null && response.get("redirect") != null) {
			model.addAllAttributes(response);
			session.setAttribute("location", model.getAttribute("location"));
            return response.get("redirect").toString();
        }

		return "401";
	}
	

	/*
	 * 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 String updateInstanciaTascaEvidencia(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Map<String,String> params, 
		@RequestParam(required = true) List<MultipartFile> evidencias) throws IllegalStateException, IOException {
			
		HashMap<String, Object> response =
                pc.updateInstanciaTascaEvidencia(id, params, evidencias, ((Usuari) auth.getPrincipal()).getUsuari());
        if (response != null && response.get("ammount") != null) {
			model.addAllAttributes(response);
			session.setAttribute("location", model.getAttribute("location"));
			return response.get("ammount").toString();
        }
	
		return "0";
	}
	
	/*
	 * 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 String updateInstanciaTasca(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Map<String,String> params, 
			@RequestParam(required = false) List<MultipartFile> evidencias) throws IllegalStateException, IOException, InterruptedException {
		
		HashMap<String, Object> response =
                pc.updateInstanciaTasca(id, params, evidencias, ((Usuari) auth.getPrincipal()).getUsuari());
        if (response != null && response.get("redirect") != null) {
			model.addAllAttributes(response);
			session.setAttribute("location", model.getAttribute("location"));
			return response.get("redirect").toString();
        }

		return "401";
	}
	

	/*
	 * 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 String saveDraft(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam String text, 
							@RequestParam boolean manual) {
		HashMap<String, Object> response =
                pc.saveDraft(session.getAttribute("location").toString(), id, text, manual, ((Usuari) auth.getPrincipal()).getUsuari());
		if (response != null && response.get("date") != null) {
			model.addAllAttributes(response);
			session.setAttribute("location", model.getAttribute("location"));
			return response.get("date").toString();
        }
		
		return "401";
	}

	/*
	 * 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 String getDrafts(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id) {
		HashMap<String, Object> response =
                pc.getDrafts(id);
		if (response != null && response.get("redirect") != null) {
			model.addAllAttributes(response);
			return response.get("redirect").toString();
        }

		return "401";
	}

	/*
	 * 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(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Timestamp dataMod) {
		return pc.getDraft(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(Model model, Authentication auth, HttpSession session, @PathVariable BigInteger id, @RequestParam Timestamp dataMod) {
		return pc.restoreDraft(id, dataMod);
	}
}