package mx.gob.jumapacelaya.api;

import com.mysql.cj.protocol.x.Notice;
import com.nimbusds.jose.shaded.gson.*;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import mx.gob.jumapacelaya.models.RedmineUser;
import mx.gob.jumapacelaya.models.Ticket;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class RedmineClient {

    private static final int PAGE_SIZE = 25;
    static String REDMINE_URL;
    static String API_KEY;
    public static final Gson GSON = new Gson();

    public RedmineClient(@Value("${redmine.url}") String redmineUrl, @Value("${redmine.api_key}") String apiKey) {
        REDMINE_URL = redmineUrl;
        API_KEY = apiKey;

    }

    //AQUI OBTENGO LOS TICKETS DESDE REDMINE
    public List<Ticket> getTickets(RedmineUser user, boolean includeClosed) {
        List<Ticket> tickets = new ArrayList<>();
        HttpClient client = HttpClient.newHttpClient();
        int offset = 0;

        // Si includeClose es true, incluira todos los tikets si no, incluira solo los que estan abiertos
        String statusFilter = includeClosed ? "&status_id=*" : "&status_id=open";


        while (true) {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(REDMINE_URL + "/issues.json?key=" + user.getKey() + statusFilter + "&offset=" + offset))
                    .header("Content-Type", "application/json")
                    .build();

            try {
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                if (response.statusCode() == 200) {
                    String responseBody = response.body();
                    List<Ticket> pageTickets = parseTickets(responseBody);
                    tickets.addAll(pageTickets);
                    if (pageTickets.size() < PAGE_SIZE) {
                        break;
                    }
                    offset += PAGE_SIZE;
                } else {
                    System.err.println("Error en la respuesta: " + response.statusCode());
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }
        System.out.println("Total tickets obtenidos: " + tickets.size());
        return tickets;
    }


    //AQUI OBTENGO LOS TICKETS DESDE REDMINE
    public List<Ticket> getTicketsAuthor(RedmineUser user, boolean includeClosed) {
        List<Ticket> tickets = new ArrayList<>();
        HttpClient client = HttpClient.newHttpClient();
        int offset = 0;

        // Si includeClose es true, incluira todos los tikets si no, incluira solo los que estan abiertos
        String statusFilter = includeClosed ? "&status_id=*" : "&status_id=open";


        while (true) {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create(REDMINE_URL + "/issues.json?key=" + user.getKey() + "&author_id=" + user.getId() + statusFilter + "&offset=" + offset))
                    .header("Content-Type", "application/json")
                    .build();

            try {
                HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
                if (response.statusCode() == 200) {
                    String responseBody = response.body();
                    List<Ticket> pageTickets = parseTickets(responseBody);
                    tickets.addAll(pageTickets);
                    if (pageTickets.size() < PAGE_SIZE) {
                        break;
                    }
                    offset += PAGE_SIZE;
                } else {
                    System.err.println("Error en la respuesta: " + response.statusCode());
                    break;
                }
            } catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }
        System.out.println("Total tickets obtenidos: " + tickets.size());
        return tickets;
    }


    // Aquí se parsean todos los tickets que existen y se les da un formato con los campos a mostrarse
    private List<Ticket> parseTickets(String json) {
        List<Ticket> tickets = new ArrayList<>();
        try {
            JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
            JsonArray issues = jsonObject.getAsJsonArray("issues");
            if (issues != null) {
                for (JsonElement issueElement : issues) {
                    JsonObject issue = issueElement.getAsJsonObject();

                    // Verifica y obtiene el ID
                    int id = issue.has("id") && !issue.get("id").isJsonNull() ? issue.get("id").getAsInt() : 0;

                    // Verifica y obtiene el subject
                    String subject = issue.has("subject") && !issue.get("subject").isJsonNull() ? issue.get("subject").getAsString() : "";

                    // Verifica y obtiene la descripción
                    String description = issue.has("description") && !issue.get("description").isJsonNull() ? issue.get("description").getAsString() : "";

                    // Verifica y obtiene el status
                    String status = "Unknown";
                    if (issue.has("status") && !issue.get("status").isJsonNull()) {
                        JsonObject statusObject = issue.getAsJsonObject("status");
                        if (statusObject.has("name") && !statusObject.get("name").isJsonNull()) {
                            status = statusObject.get("name").getAsString();
                        }
                    }

                    // Verifica y obtiene la fecha de creación
                    String dateString = issue.has("created_on") && !issue.get("created_on").isJsonNull() ? issue.get("created_on").getAsString() : "";
                    LocalDate dateCreate = null;
                    if (!dateString.isEmpty()) {
                        try {
                            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
                            dateCreate = LocalDate.parse(dateString, formatter);
                        } catch (DateTimeParseException e) {
                            System.err.println("Error al parsear la fecha: " + dateString);
                            e.printStackTrace();
                        }
                    }

                    // Verifica y obtiene la fecha de cierre
                    String closeDateString = issue.has("closed_on") && !issue.get("closed_on").isJsonNull() ? issue.get("closed_on").getAsString() : "";
                    LocalDate dateClose = null;
                    if (!closeDateString.isEmpty()) {
                        try {
                            DateTimeFormatter formatter = DateTimeFormatter.ISO_DATE_TIME;
                            dateClose = LocalDate.parse(closeDateString, formatter);
                        } catch (DateTimeParseException e) {
                            System.err.println("Error al parsear la fecha de cierre: " + closeDateString);
                            e.printStackTrace();
                        }
                    }


                    //Verifica y obtiene el ID del tipo de ticket
                    Integer trackerId = null;
                    if (issue.has("tracker") && !issue.get("tracker").isJsonNull()) {
                        JsonObject trackerObject = issue.getAsJsonObject("tracker");
                        if (trackerObject.has("id") && !trackerObject.get("id").isJsonNull()) {
                            trackerId = trackerObject.get("id").getAsInt();
                        }
                    }


                    // Agrega el ticket a la lista
                    tickets.add(new Ticket(id, subject, description, status,
                                dateCreate != null ? dateCreate.toString() : "",
                                dateClose != null ? dateClose.toString() : "",
                                trackerId, "Tipo Desconocido"));
                }
            } else {
                System.out.println("La respuesta JSON no contiene la clave 'issues'");
            }
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("Ocurrió un error al parsear los tickets: " + e.getMessage());
        }
        return tickets;
    }

    public RedmineUser getMyAccount(String username) {
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(REDMINE_URL + "/my/account.json"))
                .header("Content-Type", "application/json")
                .header("X-Redmine-Switch-User", username)
                .header("X-Redmine-API-Key", API_KEY)
                .GET()
                .build();
        try {
            HttpClient client = HttpClient.newHttpClient();
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            JsonObject jsonObject = JsonParser.parseString(response.body()).getAsJsonObject();
            JsonObject userJson = jsonObject.get("user").getAsJsonObject();

            RedmineUser user = new RedmineUser();
            user.setId(userJson.get("id").getAsInt());
            user.setLogin(userJson.get("login").getAsString());
            user.setFirstname(userJson.get("firstname").getAsString());
            user.setLastname(userJson.get("lastname").getAsString());
            user.setMail(userJson.get("mail").getAsString());
            user.setKey(userJson.get("api_key").getAsString());
            return user;

            //return response.body();
        } catch (IOException | InterruptedException e) {
            e.printStackTrace();
            return null;
        }
    }


    public static RedmineUser createRedmineUser(String username, String firstname, String lastname, String mail) {
        HttpClient client = HttpClient.newHttpClient();
        Map<String, Object> user = new HashMap<>();
        user.put("login", username);
        user.put("firstname", firstname);
        user.put("lastname", lastname);
        user.put("mail", mail);
        user.put("auth_source_id", "1");

        Map<String, Object> payload = new HashMap<>();
        payload.put("user", user);
        String jsonPayload = new Gson().toJson(payload);
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(REDMINE_URL + "/users.json"))
                .header("Content-Type", "application/json")
                .header("X-Redmine-API-Key", API_KEY)
                .POST(HttpRequest.BodyPublishers.ofString(jsonPayload))
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());

            JsonObject jsonObject = JsonParser.parseString(response.body()).getAsJsonObject();
            JsonObject userJson = jsonObject.get("user").getAsJsonObject();

            RedmineUser newUser = new RedmineUser();
            newUser.setId(userJson.get("id").getAsInt());
            newUser.setLogin(userJson.get("login").getAsString());
            newUser.setFirstname(userJson.get("firstname").getAsString());
            newUser.setLastname(userJson.get("lastname").getAsString());
            newUser.setMail(userJson.get("mail").getAsString());

            return newUser;

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

    //AQUI OBTENGO A LOS USUARIOS
    //Se devuelven en formato Json
    public RedmineUser getUserByUsername(String username) {
        HttpClient client = HttpClient.newHttpClient();
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(REDMINE_URL + "/users.json?name=" + username ))
                .header("Content-Type", "application/json")
                .header("X-Redmine-API-Key", API_KEY)
                .build();

        try {
            HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
            if (response.statusCode() == 200) {
                String responseBody = response.body();
                System.out.println("Datos del usuario " + responseBody);
                return parseUser(responseBody);
            } else {
                System.err.println("Error en la respuesta: " + response.statusCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    //Aqui se parsean a los usuarios y se les da un formato con los campos a mostrarse
    private RedmineUser parseUser(String json) {
        JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
        JsonObject userJson = jsonObject.getAsJsonArray("users").get(0).getAsJsonObject();

        RedmineUser user = new RedmineUser();
        user.setId(userJson.get("id").getAsInt());
        user.setLogin(userJson.get("login").getAsString());
        user.setFirstname(userJson.get("firstname").getAsString());
        user.setLastname(userJson.get("lastname").getAsString());
        user.setMail(userJson.get("mail").getAsString());
        //user.setKey(userJson.get("key").getAsString());
        return user;
    }


    /*Este metodo sirve para actualizar el estatus de los tickets
    en este caso se actualiza al estatus TERMINADO */
    public void closeTicket(int ticketId, RedmineUser user) throws IOException, InterruptedException {
        int closedStatusId = 9; //este es el ID del estado TERMINADO, se debe poner el id a según corresponda

        Map<String, Object> payload = new HashMap<>();
        Map<String, Object> issue = new HashMap<>();
        issue.put("status_id", closedStatusId);
        payload.put("issue", issue);
        String jsonPayload = GSON.toJson(payload);

        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(REDMINE_URL + "/issues/" + ticketId + ".json?key=" + user.getKey()))
                .header("Content-Type", "application/json")
                .PUT(HttpRequest.BodyPublishers.ofString(jsonPayload))
                .build();

        HttpClient client = HttpClient.newHttpClient();
        HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());
        if (response.statusCode() == 204) {
            String responseBody = response.body();
            System.out.println("Ticket " + ticketId + " cerrado correctamente.");
        } else {
            System.err.println("Error al cerrar el ticket: " + response.statusCode());
            System.err.println(response.body());
        }
    }
}
