package mx.gob.jumapacelaya.views.crearnuevoticket;

import com.nimbusds.jose.shaded.gson.JsonArray;
import com.nimbusds.jose.shaded.gson.JsonObject;
import com.nimbusds.jose.shaded.gson.JsonParser;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.component.upload.Upload;
import com.vaadin.flow.component.upload.UploadI18N;
import com.vaadin.flow.component.upload.receivers.MultiFileMemoryBuffer;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.api.RedmineClient;
import mx.gob.jumapacelaya.models.RedmineUser;
import mx.gob.jumapacelaya.services.UserService;
import mx.gob.jumapacelaya.views.MainLayout;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

@Route(value = "", layout = MainLayout.class)
@PermitAll
@PageTitle("Nuevo ticket")
public class CrearnuevoTicketView extends VerticalLayout {

    private final RedmineClient api;
    private final UserService userService;
    private MultiFileMemoryBuffer buffer;
    private Upload uploadFile;
    private String selectedTrackerId;
    private Span ticketTypeDesc;

    public CrearnuevoTicketView(RedmineClient api, UserService service) {
        this.api = api;
        this.userService = service;
        this.buffer = new MultiFileMemoryBuffer();
        this.uploadFile = createUploadComponent();
        this.ticketTypeDesc = new Span();

        RedmineUser user = userService.getRedmineUser();

        //Componentes principales de la UI
        ComboBox<String> tipoTickets = createTicketTypeComboBox();
        TextField asunto = createTextField("Asunto", "1000px");
        TextArea descripcion = createTextArea("Descripcion", "1000px", "250px");

        // Marcar campos como obligatorios
        tipoTickets.setRequiredIndicatorVisible(true);
        asunto.setRequiredIndicatorVisible(true);
        descripcion.setRequiredIndicatorVisible(true);

        uploadFile.addSucceededListener(event -> handleFileUpload(event.getFileName()));

        //Configuracion del Boton
        Button createButton = new Button("Enviar ticket", event -> handleCreateButton(user, tipoTickets, asunto, descripcion));
        createButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY, ButtonVariant.LUMO_LARGE);
        createButton.getStyle().set("background-color", "#691B31");

        uploadFile.addSucceededListener(event -> {
            handleFileUpload(event.getFileName());
            createButton.setEnabled(true);
        });

        uploadFile.addFailedListener(event -> {
            // Habilitar el botón en caso de fallo
           /* createButton.setEnabled(true);*/
        });

        uploadFile.addStartedListener(event -> {
            createButton.setEnabled(false);
        });

        createButton.setEnabled(true);



        //Alineacion de los componentes ComboBox Tipos de tickets y Descripcion del tipo de ticket
        HorizontalLayout firstFields = new HorizontalLayout(tipoTickets, ticketTypeDesc);


        //Alineacion de los componentes de asunto y descripcion
        VerticalLayout fieldsLayout = new VerticalLayout(asunto, descripcion);
        fieldsLayout.setAlignItems(Alignment.START);


        //Alineacion del Boton y del Upload
        HorizontalLayout buttonLayout = new HorizontalLayout(uploadFile, createButton);
        buttonLayout.setAlignItems(Alignment.START);
        buttonLayout.setMargin(true);


        //Estilizacion del Span que muestra la descripcion del tipo de ticket
        ticketTypeDesc.getStyle().set("font-size", "15px");
        ticketTypeDesc.getStyle().set("background-color", "#edeef0");
        ticketTypeDesc.getStyle().set("border-radius", "5px");
        ticketTypeDesc.getStyle().set("padding", "10px");



        add(new H2("Crear nuevo ticket"), firstFields, fieldsLayout, buttonLayout);
    }

    private Upload createUploadComponent() {
        buffer = new MultiFileMemoryBuffer();
        Upload uploadFile = new Upload(buffer);
        uploadFile.setMaxFiles(5);
        uploadFile.setDropAllowed(true);

        UploadI18N i18N = new UploadI18N();
        UploadI18N.Uploading uploading = i18N.getUploading();
        if (uploading == null) {
            uploading = new UploadI18N.Uploading();
            i18N.setUploading(uploading);
        }

        UploadI18N.Uploading.Error error = uploading.getError();
        if (error == null) {
            error = new UploadI18N.Uploading.Error();
            uploading.setError(error);
        }

        error.setUnexpectedServerError("No se pudo cargar el archivo. Por favor, intentalo de nuevo");
        error.setServerUnavailable("El archivo es demasiado grande. El tamaño máximo permitido es de 10 MB.");
        error.setForbidden("Archivo no permitido");

        Paragraph pista = new Paragraph("No. de archivos permitidos: 5");

        uploadFile.setI18n(i18N);
        return uploadFile;
    }

    private ComboBox<String> createTicketTypeComboBox() {
        ComboBox<String> tipoTickets = new ComboBox<>("Tipo de ticket");
        tipoTickets.setPlaceholder("Seleccione un tipo de ticket");

        Map<String, RedmineClient.TicketType> ticketTypesMap = api.getTicketTypes();
        Set<String> ticketTypesSet = Set.of("Acceso/Permiso/Bajas", "Soporte de Software", "Capacitacion de Software",
                "Configuracion de Software", "Digitalizacion GIS", "Documento", "Funcionalidad", "Reporte",
                "Mantenimiento Correctivo", "Desarrollo de Software", "Actividad","Entrega de Consumibles","Instalación/Configuracion GIS");
        List<String> filteredTicketTypes = ticketTypesMap.keySet().stream()
                .filter(ticketTypesSet::contains)
                .collect(Collectors.toList());
        tipoTickets.setItems(filteredTicketTypes);

        tipoTickets.addValueChangeListener(event -> {
            String selectedType = event.getValue();
            RedmineClient.TicketType ticketType = ticketTypesMap.get(selectedType);
            ticketTypeDesc.setText(ticketType != null ? ticketType.getDescription() : "Descripcion no disponible para este tipo de ticket");
            selectedTrackerId = ticketType != null ? ticketType.getId() : null;
        });
        return tipoTickets;
    }

    private TextField createTextField(String label, String width) {
        TextField textField = new TextField(label);
        textField.setWidth(width);
        return textField;
    }

    private TextArea createTextArea(String label, String width, String height) {
        TextArea textArea = new TextArea(label);
        textArea.setWidth(width);
        textArea.setHeight(height);
        return textArea;
    }


    private void handleFileUpload(String fileName) {
        try (InputStream inputStream = buffer.getInputStream(fileName);
             ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) {

            byte[] bufferArray = new byte[1024];
            int bytesRead;
            while ((bytesRead = inputStream.read(bufferArray)) != -1) {
                outputStream.write(bufferArray, 0, bytesRead);
            }
        } catch (IOException e) {
            Notification.show("Error al leer el archivo: " + e.getMessage(), 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void handleCreateButton(RedmineUser user, ComboBox<String> tipoTickets, TextField asunto, TextArea descripcion) {
        if (user.getKey() == null || user.getKey().isEmpty()) {
            Notification.show("No se encontró la API key en la sesión.", 5000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
            return;
        }

        if (selectedTrackerId == null) {
            Notification.show("Por favor seleccione un tipo de ticket.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_WARNING);
            return;
        }

        if (asunto.isEmpty()) {
            Notification.show("El asunto es obligatorio.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_WARNING);
            return;
        }

        if (descripcion.isEmpty()) {
            Notification.show("La descripción es obligatoria.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_WARNING);
            return;
        }

        Map<String, String> issueDetails = new HashMap<>();
        issueDetails.put("project_id", "soporte-tecnico-t-i");
        issueDetails.put("subject", asunto.getValue());
        issueDetails.put("description", descripcion.getValue());
        issueDetails.put("tracker_id", selectedTrackerId);

        JsonArray uploadsJsonArray = new JsonArray();
        if (!buffer.getFiles().isEmpty()) {
            buffer.getFiles().forEach(fileName -> {
            try (InputStream inputStream = buffer.getInputStream(fileName)) {
                byte[] fileContent = inputStream.readAllBytes();
                String fileToken = api.uploadFile(fileContent, fileName);
                JsonObject uploadJson = new JsonObject();
                uploadJson.addProperty("token", fileToken);
                uploadJson.addProperty("filename", fileName);
                uploadJson.addProperty("content_type", buffer.getFileData(fileName).getMimeType());
                uploadsJsonArray.add(uploadJson);
            } catch (IOException e) {
                Notification.show("Error al cargar el archivo: " + e.getMessage(), 3000, Notification.Position.MIDDLE)
                        .addThemeVariants(NotificationVariant.LUMO_ERROR);
                }
            });
        }

        String response = api.createIssue(issueDetails, uploadsJsonArray, user.getKey());
        handleResponse(response, asunto, descripcion, tipoTickets);
    }

    private void handleResponse(String response, TextField asunto, TextArea descripcion, ComboBox<String> tipoTickets) {
        if (response.startsWith("{\"issue\":")) {
            JsonObject jsonResponse = JsonParser.parseString(response).getAsJsonObject();
            int issueNumber = jsonResponse.getAsJsonObject("issue").get("id").getAsInt();
            Notification.show("Su ticket se ha enviado correctamente! Numero de ticket: #" + issueNumber, 5000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
            resetForm(asunto, descripcion, tipoTickets);
        } else {
            Notification.show("Error al crear el ticket: " + response, 5000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void resetForm(TextField asunto, TextArea descripcion, ComboBox<String> tipoTickets) {
        asunto.clear();
        descripcion.clear();
        tipoTickets.clear();
        ticketTypeDesc.setText("");

        asunto.setInvalid(false);
        descripcion.setInvalid(false);
        tipoTickets.setInvalid(false);

        buffer = new MultiFileMemoryBuffer();
        uploadFile.setReceiver(buffer);
        uploadFile.clearFileList();
    }
}
