package es.uv.saic.service;

import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.util.Base64;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;

import es.uv.saic.domain.InstanciaTasca;
import es.uv.saic.domain.PlantillaComentario;
import es.uv.saic.domain.PlantillaConversation;


@Service
public class PlantillaService {
	@Value("${saic.data.tmpPath}")
	private String tmpPath;
	@Value("${saic.data.templates.logoPath}")
	private String logoPath;

	@Value("${saic.url.core.domain}")
	private String uriCore;


	public byte[] toPDF(String content, Optional<BigInteger> idtascai) throws IOException, InterruptedException {
		content = content.replace("<p><!-- pagebreak --></p>", "<p class=\"pagebreak\"><!-- pagebreak --></p>");
		Document d = Jsoup.parse(content, "UTF8");
		d.head().append("<style>"
				+ "@page{size: 297mm 210mm;} "
				+ "html{ max-width:297mm; max-height:210mm; margin:0; padding:0; transform:scale(0.925); transform-origin:left top; } "
				+ "table { padding:2px !important; }"
				+ "th, td { padding:2px !important; }"
				+ ".pagebreak { page-break-before:always; }"
				+ "</style>");
		List<Element> trs = d.getElementsByTag("tr");
		for(Element t : trs) {
			if(t.hasAttr("height")) {
				t.removeAttr("height");
			}
			if(t.hasAttr("style")) {
				String style = t.attr("style");
				style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
				t.attr("style", style);
			}
		}
		List<Element> tds = d.getElementsByTag("td");
		for(Element t : tds) {
			if(t.hasAttr("height")) {
				t.removeAttr("height");
			}
			if(t.hasAttr("style")) {
				String style = t.attr("style");
				style = style.replaceAll("height:[ \\d.pxcmin]{1,};", "");
				t.attr("style", style);
			}
		}
		List<Element> ignore = d.getElementsByClass("pdfignore");
		for(Element e: ignore) {
			e.remove();
		}
		
		if(idtascai.isPresent()) {
			InstanciaTasca ita = findById(idtascai.get());
			if(ita.getTasca().getRol().getNomRol().equals("u_uq")) {
				d.body().append(this.parseComments(d.html()));
			}
		}
		
		d.body().append(this.parseComments(d.html()));
				
		String basecommand = "google-chrome --headless --disable-gpu --no-pdf-header-footer --run-all-compositor-stages-before-draw --no-sandbox";	
		File dst = File.createTempFile("saic-pdfpreview-", ".tmp.pdf", new File(tmpPath));
		File src = File.createTempFile("saic-pdfpreview-", ".tmp.html", new File(tmpPath));
		src.deleteOnExit();
		dst.deleteOnExit();
		
		PrintWriter out = new PrintWriter(src.getAbsolutePath());
		out.println(d.html());
		out.flush();
		out.close();
		ProcessBuilder pb = new ProcessBuilder("bash", "-c", basecommand+" --print-to-pdf='"+dst+"' "+src.getAbsolutePath());
		Process pr = pb.start();
		pr.waitFor();
				
		byte[] bytes = Files.readAllBytes(dst.toPath());
		src.delete();
		dst.delete();
		
		return bytes;
	}
	
	private InstanciaTasca findById(BigInteger id) {
		URI uriObj = URI.create(uriCore + "/instanciatasca/" + id);
		ObjectMapper mapper = new ObjectMapper();
		InstanciaTasca instanciaTasca = null;

		try {
			HttpClient httpClient = HttpClient.newHttpClient();

			HttpRequest request = HttpRequest.newBuilder()
					.uri(uriObj)
					.header("Content-Type", "application/json")
					.POST(HttpRequest.BodyPublishers.noBody())
					.build();

			HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

			if (response.statusCode() == HttpURLConnection.HTTP_OK) {
				instanciaTasca = mapper.readValue(response.body(), InstanciaTasca.class);
			} else {
				System.err.println("Error al obtener instancia: " + response.statusCode() + " -> " + response.body());
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		return instanciaTasca;
	}


	private String parseComments(String content) throws JsonParseException, JsonMappingException, IOException {
		// <!--tinycomments\|2\.1\|data:application\/json;base64,([A-Za-z0-9]*)=-->
		Pattern pattern = Pattern.compile("\\<\\!\\-\\-tinycomments\\|2\\.1\\|data\\:application\\/json\\;base64\\,([A-Za-z0-9\\/\\+\\\\]*)\\=*\\-\\-\\>");
		Matcher matcher = pattern.matcher(content);
		String rawComments = "";
		if(matcher.find()) {
			byte[] decoded = Base64.getDecoder().decode(matcher.group(1));
			rawComments = new String(decoded, "UTF-8");
			
			if(rawComments.length() < 10) {
				return "";
			}
			
			rawComments = rawComments.replaceAll("^.", "[");
			rawComments = rawComments.replaceAll(".$", "]");
			rawComments = rawComments.replaceAll("\"mce-conversation\\_\\d*\":", "");
			
			ObjectMapper mapper = new ObjectMapper();
			List<PlantillaConversation> comments = mapper.readValue(rawComments, new TypeReference<List<PlantillaConversation>>(){});
			
			String tabComments =  "<p class=\"pagebreak\"><!-- pagebreak --></p>"
								+ "<h3>COMENTARIOS GENERADOS DURANTE LA REVISIÓN DEL DOCUMENTO</h3>"
								+ "<h3><small>Nota: Esta página no será visible en la versión final publicada del documento.</small></h3>"
								+ "<table style=\"border-collapse: collapse; width: 297mm; border-width: 1px; border-spacing: 0px; border-color: rgb(149, 165, 166); margin-left: 0px; margin-right: auto;\" border=\"1\" width=\"297mm\" cellspacing=\"0\" cellpadding=\"8\">"
								+ "<thead>"
								+ "    <tr style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\" bgcolor=\"#153d63\">"
								+ "      <th style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166); color:white;\" scope=\"col\">Usuario</th>"
								+ "      <th style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166); color:white;\" scope=\"col\">Nombre</th>"
								+ "      <th style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166); color:white;\" scope=\"col\">Comentario</th>"
								+ "    </tr>"
								+ "  </thead>"
								+ "<tbody>";
			for(PlantillaConversation conv: comments) {
				for(PlantillaComentario c: conv.getComments()) {
					tabComments += ("<tr style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\"> "
								  + "  <td style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\">"+c.getAuthor()+"</td>"
								  + "  <td style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\">"+c.getAuthorName()+"</td>"
								  + "  <td style=\"padding: 0px; border-width: 1px; border-color: rgb(149, 165, 166);\">"+c.getContent()+"</td>"
								  + "</tr> ");
				}
			}
			tabComments += "</tbody></table>";
			return tabComments;
		}
		
		return "";
	}
	
	
}
