package mx.gob.jumapacelaya.ui;

import com.vaadin.flow.component.UI;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.checkbox.Checkbox;
import com.vaadin.flow.component.checkbox.CheckboxGroup;
import com.vaadin.flow.component.checkbox.CheckboxGroupVariant;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.dependency.CssImport;
import com.vaadin.flow.component.dialog.Dialog;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.grid.GridVariant;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.icon.Icon;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.FlexComponent;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.popover.Popover;
import com.vaadin.flow.component.popover.PopoverPosition;
import com.vaadin.flow.component.progressbar.ProgressBar;
import com.vaadin.flow.component.richtexteditor.RichTextEditor;
import com.vaadin.flow.data.renderer.ComponentRenderer;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.StreamRegistration;
import com.vaadin.flow.server.StreamResource;
import jakarta.annotation.security.PermitAll;
import mx.gob.jumapacelaya.api.RedmineClient;
import mx.gob.jumapacelaya.api.ServerProperties;
import mx.gob.jumapacelaya.models.RedmineUser;
import mx.gob.jumapacelaya.models.Ticket;
import mx.gob.jumapacelaya.services.UserService;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.ss.util.CellRangeAddress;
import org.apache.poi.util.IOUtils;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vaadin.lineawesome.LineAwesomeIcon;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Stream;


@PermitAll
@PageTitle("Actividades Diarias")
@Route(value = "actdiaria", layout = MainLayout.class)
@CssImport("./themes/sistema-mantenimiento/styles.css")
public class ActDiariaView extends VerticalLayout {

    private static final Logger log = LoggerFactory.getLogger(ActDiariaView.class);
    private final RedmineClient redmineClient;
    private final UserService userService;
    private final Grid<Ticket> grid;
    private final HorizontalLayout showColumnsLyt;
    private final Button btnColumns;
    private final Button btnExport;
    private final HorizontalLayout opcionesLyt;
    private Checkbox chkSoloAbiertos;
    private DatePicker fechaDesde;
    private DatePicker fechaHasta;
    private Button btnBuscar;

    public ActDiariaView(ServerProperties properties, RedmineClient redmineClient, UserService userService) {
        this.userService = userService;
        this.redmineClient = redmineClient;
        this.grid = new Grid<>(Ticket.class, false);

        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");

        // Layout de opciones
        opcionesLyt = new HorizontalLayout();
        opcionesLyt.setWidthFull();
        opcionesLyt.setAlignItems(Alignment.BASELINE);
        //opcionesLyt.setMargin(false);
        opcionesLyt.getStyle()
                .set("box-shadow", "0 4px 8px rgba(0,0,0,0.2)")
                .set("border-radius", "10px")
                //.set("background-color", "white")
                .set("padding", "1rem")
                .set("margin", "1rem auto");

        // Checkbox para ver solo abiertos
        chkSoloAbiertos = new Checkbox("Ver solo abiertos");
        chkSoloAbiertos.setValue(false); // inicial: mostrar cerrados

        fechaDesde = new DatePicker();
        fechaDesde.setPlaceholder("Fecha desde:");
        fechaDesde.setLocale(new Locale("es", "MX"));
        DatePicker.DatePickerI18n i18n = new DatePicker.DatePickerI18n()
                .setWeekdays(List.of("Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"))
                .setWeekdaysShort(List.of("Dom","Lun","Mar","Mié","Jue","Vie","Sab"))
                .setMonthNames(List.of("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"))
                .setFirstDayOfWeek(1)
                .setToday("Hoy")
                .setCancel("Cancelar")
                .setDateFormat("dd/MM/yyyy");
        fechaDesde.setI18n(i18n);

        fechaHasta = new DatePicker();
        fechaHasta.setPlaceholder("Fecha hasta:");
        fechaHasta.setLocale(new Locale("es", "MX"));
        DatePicker.DatePickerI18n i18nh = new DatePicker.DatePickerI18n()
                .setWeekdays(List.of("Domingo","Lunes","Martes","Miércoles","Jueves","Viernes","Sábado"))
                .setWeekdaysShort(List.of("Dom","Lun","Mar","Mié","Jue","Vie","Sab"))
                .setMonthNames(List.of("Enero","Febrero","Marzo","Abril","Mayo","Junio","Julio","Agosto","Septiembre","Octubre","Noviembre","Diciembre"))
                .setFirstDayOfWeek(1)
                .setToday("Hoy")
                .setCancel("Cancelar")
                .setDateFormat("dd/MM/yyyy");
        fechaHasta.setI18n(i18nh);

        btnBuscar = new Button("Buscar", VaadinIcon.SEARCH.create());

        // Listener del checkbox
        chkSoloAbiertos.addValueChangeListener(e -> {
            boolean soloAbiertos = e.getValue(); // marcado = abiertos
            fechaDesde.setEnabled(!soloAbiertos);
            fechaHasta.setEnabled(!soloAbiertos);
            btnBuscar.setEnabled(!soloAbiertos);

            grid.getDataProvider().refreshAll();
        });

        // Estado inicial
        fechaDesde.setEnabled(true);
        fechaHasta.setEnabled(true);
        btnBuscar.setEnabled(true);
        btnBuscar.addClickListener(e -> filtrarTickets());

        // Cargar tickets iniciales (cerrados)
        loadTickets(false);

        opcionesLyt.add(chkSoloAbiertos, fechaDesde, fechaHasta, btnBuscar);


        grid.setItems(
                query -> {
                    try {
                        return redmineClient.getTickets(
                                userService.getRedmineUser(),
                                chkSoloAbiertos.getValue(),
                                query.getOffset(),
                                query.getLimit(),
                                fechaDesde.getValue(),
                                fechaHasta.getValue()
                        ).stream();
                    } catch (Exception e) {
                        log.error("Error al cargar tickets", e);
                        return Stream.empty();
                    }
                },
                query -> redmineClient.getTotalTickets(
                        userService.getRedmineUser(),
                        chkSoloAbiertos.getValue(),
                        fechaDesde.getValue(),
                        fechaHasta.getValue()
                )
        );
        // Configuración de columnas del grid
        grid.addColumn(Ticket::getId).setHeader("No.")
                .setAutoWidth(true)
                .setSortable(true);

        grid.addColumn(Ticket::getType)
                .setHeader("Tipo")
                .setAutoWidth(true)
                .setKey("tipo");

        grid.addColumn(ticket -> ticket.tiempoEst(ticket.getTrackerId()))
                .setHeader("Tiempo estimado")
                .setAutoWidth(true)
                .setKey("tiempoEst");

        grid.addColumn(ticket -> {
                    LocalDateTime fecha = ticket.getDateCreate();
                    return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) : "";
                }).setHeader("Fecha creación")
                .setAutoWidth(true)
                .setSortable(true)
                .setKey("fechaCreacion");

        grid.addColumn(ticket -> {
                    LocalDateTime fecha = ticket.getDateClose();
                    return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) : "";
                }).setHeader("Fecha cierre")
                .setAutoWidth(true)
                .setSortable(true)
                .setKey("fechaCierre");

        grid.addColumn(ticket -> {
                    LocalDateTime fecha = ticket.getUpdateOn();
                    return fecha != null ? fecha.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss")) : "";
                }).setHeader("Fecha actualización")
                .setAutoWidth(true)
                .setKey("fechaActualizacion");

        grid.addColumn(ticket -> {
            if (ticket.getDateCreateLocal() != null && ticket.getDateCloseLocal() != null) {
                LocalDateTime inicio = ticket.getDateCreateLocal();
                LocalDateTime fin = ticket.getDateCloseLocal();

                long horasReales = ChronoUnit.HOURS.between(inicio, fin);
                Double horasEstimadas = ticket.getEstimatedHrs();

                if (horasEstimadas != null) {
                    return horasReales <= horasEstimadas ? "✅ En tiempo" : "⚠️ Excedido";
                } else {
                    return "Sin estimación";
                }
            } else {
                return "";
            }
        }).setHeader("Situación").setAutoWidth(true).setKey("cumplimientoHoras");

        grid.addColumn(createStatusRender())
                .setHeader("Estado")
                .setKey("estado");


        grid.addColumn(ticket -> {
            if (ticket.getDateCreateLocal() != null) {
                LocalDateTime fechaInicio = ticket.getDateCreateLocal();
                LocalDateTime fechaFin = (ticket.getDateCloseLocal() != null)
                        ? ticket.getDateCloseLocal()
                        : LocalDateTime.now();
                long dias = ChronoUnit.DAYS.between(fechaInicio, fechaFin);
                return dias + " días";
            } else {
                return "";
            }
        }).setHeader("Duración").setAutoWidth(true).setSortable(true).setKey("duracion");


        grid.addColumn(ticket ->
                        ticket.getAuthor() != null ? ticket.getAuthor().getUsername() : "")
                .setHeader("Autor")
                .setAutoWidth(true)
                .setKey("autor");


        grid.addColumn(Ticket::getSubject)
                .setHeader("Asunto")
                .setWidth("25rem")
                .setKey("asunto");


        grid.addComponentColumn(ticket -> {
            Button btnVer = new Button(new Icon(VaadinIcon.EYE));
            btnVer.addClickListener(event -> showDescription(ticket));
            return btnVer;
        });

        grid.addThemeVariants(GridVariant.LUMO_WRAP_CELL_CONTENT);
        grid.addThemeVariants(GridVariant.LUMO_ROW_STRIPES);
        grid.setSizeFull();

        // Botón para mostrar/ocultar columnas
        btnColumns = new Button(VaadinIcon.GRID_H.create());
        // Botón para exportar
        btnExport = new Button("Exportar", LineAwesomeIcon.FILE_EXCEL.create());
        btnExport.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        btnExport.addClickListener(e -> exportTicketsCerrados());
        showColumnsLyt = new HorizontalLayout(btnExport, btnColumns);
        showColumnsLyt.setJustifyContentMode(JustifyContentMode.END);
        showColumnsLyt.setWidthFull();
        HorizontalLayout columnsSelectorLyt = new HorizontalLayout();
        columnsSelectorLyt.setAlignItems(Alignment.END);
        Popover popover = new Popover();
        popover.setModal(true);
        popover.setBackdropVisible(true);
        popover.setPosition(PopoverPosition.BOTTOM_END);
        popover.setTarget(btnColumns);
        Div heading = new Div("Ver/Ocultar columnas");
        heading.getStyle().set("font-weight", "600");
        heading.getStyle().set("padding", "var(--lumo-space-xs)");
        List<String> columns = List.of("tipo","tiempoEst","asunto","autor","estado","fechaCreacion","fechaCierre","fechaActualizacion","duracion");
        CheckboxGroup<String> chkColumns = new CheckboxGroup<>();
        chkColumns.addThemeVariants(CheckboxGroupVariant.LUMO_VERTICAL);
        chkColumns.setItems(columns);
        chkColumns.setItemLabelGenerator((item) -> {
            String label = StringUtils
                    .join(StringUtils.splitByCharacterTypeCamelCase(item), " ");
            return StringUtils.capitalize(label.toLowerCase());
        });
        chkColumns.addValueChangeListener((e) -> {
            columns.forEach((key) -> {
                Grid.Column<?> col = grid.getColumnByKey(key);
                if (col != null) {
                    col.setVisible(e.getValue().contains(key));
                } else {
                    System.out.println("Columna no encontrada para: " + key);
                }
            });
        });
        Set<String> defaultColumns = Set.of("tipo","tiempoEst","fechaCreacion","fechaCierre","cumplimientoHoras","estado","duracion","autor","asunto");
        chkColumns.setValue(defaultColumns);
        popover.add(heading, chkColumns);

        // Ajustar tamaños
        grid.setSizeFull();
        setSizeFull();
        add(opcionesLyt, showColumnsLyt, grid);
        setMargin(false);
    }



    // NOTA: Ajuste en  la carga de tickets para que ahora haga LazyLoad al cargar todos los ticktes cerrados
    private void loadTickets(boolean soloAbiertos) {
        RedmineUser user = userService.getRedmineUser();

        // Invertir parámetro para que coincida con RedmineClient
        boolean paramCliente = !soloAbiertos;
    }


    private ComponentRenderer<Span, Ticket> createStatusRender() {
        return new ComponentRenderer<>(ticket -> {
            // Creamos un Span para mostrar el estado
            Span span = new Span(ticket.getStatus());

            // Estilos basados en el estado del ticket
            switch (ticket.getStatus().toLowerCase()) {
                case "rechazado":
                    String theme1 = String.format("badge %s", "error");
                    span.getElement().setAttribute("theme",theme1);
                    break;
                case "resuelto","cerrado":
                    String theme2 = String.format("badge %s", "success");
                    span.getElement().setAttribute("theme",theme2);
                    break;
                case "qa":
                    String theme3 = String.format("badge %s", "warning");
                    span.getElement().setAttribute("theme",theme3);
                    break;
                default:
                    String theme4 = String.format("badge %s", "");
                    span.getElement().setAttribute("theme",theme4);
            }

            return span;
        });
    }

    /*public ComponentRenderer<Button, Ticket> buttonTicketComponentRenderer() {
        return new ComponentRenderer<>(ticket -> {
            Button button = new Button(new Icon(VaadinIcon.EDIT) );
            button.getStyle().set("color", "#A02142");
            button.addClickListener(e -> {
                RedmineUser currentUser = userService.getRedmineUser();

                if (ticket.getTrackerId() == 13) {
                    UI.getCurrent().navigate("mantenimiento");
                } else if (ticket.getTrackerId() == 14) {
                    cerrarTicket(ticket, currentUser);
                } else {
                    Notification.show("El ticket no es de tipo Mantenimiento o Actividad.");
                }
            });
            return button;
        });
    }*/

    public void cerrarTicket(Ticket ticket, RedmineUser user) {
        try {
            //Llamar al metodo para cambiar el estado del ticket
            redmineClient.closeTicket(ticket.getId(), user);
            Notification.show("El ticket " + ticket.getId() + " se ha cerrado exitosamente.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);

            UI.getCurrent().getPage().executeJs("setTimeout(() => { window.location.reload(); }, 3000);");

        } catch (IOException | InterruptedException e) {
            log.error("Error al cerrar el ticket " + ticket.getId(), e);
            Notification.show("Error al cerrar el ticket " + ticket.getId());
        }
    }

    // Metodo para mostrar las descripciones en un componente Dialog
    private void showDescription(Ticket ticket) {

        Dialog dialog = new Dialog();
        dialog.getElement().setAttribute("arial-label", "Add note");
        dialog.setMaxHeight("500px");
        dialog.setMaxWidth("1100px");

        RichTextEditor textEditor  = new RichTextEditor();
        textEditor.setValue(ticket.getDescription());
        textEditor.setReadOnly(true);

        Button closeButton = new Button("Cerrar", new Icon(VaadinIcon.CLOSE));
        closeButton.addThemeVariants(ButtonVariant.LUMO_ERROR);
        closeButton.addClickListener(e -> dialog.close());

        HorizontalLayout buttonLayout = new HorizontalLayout(closeButton);
        buttonLayout.setWidthFull();
        buttonLayout.setJustifyContentMode(FlexComponent.JustifyContentMode.END);
        buttonLayout.add(closeButton);

        dialog.add(textEditor, buttonLayout);

        dialog.open();
    }


    // Metodo para exportar los tickets cerrados a un archivo de Excel
    private void exportTicketsCerrados() {
        final UI ui = UI.getCurrent();
        final RedmineUser user = userService.getRedmineUser();
        final LocalDate desde = fechaDesde.getValue();
        final LocalDate hasta = fechaHasta.getValue();

        if (ui == null) return;

        Dialog loadingDialog = createLoadingDialog("Generando archivo por favor espere...");
        loadingDialog.open();


        new Thread(() -> {
            try {
                // Traer TODOS los tickets cerrados, respetando fechas si están seleccionadas
                List<Ticket> ticketsCerrados = redmineClient.getAllTickets(
                        user,
                        false, // false = cerrados
                        desde,
                        hasta
                );

                Workbook workbook = new XSSFWorkbook();
                Sheet sheet = workbook.createSheet("Tickets cerrados");

                CellStyle titleStyle = workbook.createCellStyle();
                Font titleFont = workbook.createFont();
                titleFont.setBold(true);
                titleFont.setFontHeightInPoints((short) 20);
                titleStyle.setFont(titleFont);
                titleStyle.setAlignment(HorizontalAlignment.CENTER);

                CellStyle subTitleStyle = workbook.createCellStyle();
                Font subTitleFont = workbook.createFont();
                subTitleFont.setFontHeightInPoints((short) 18);
                subTitleStyle.setFont(subTitleFont);
                subTitleStyle.setAlignment(HorizontalAlignment.CENTER);

                int ultimaCol = 10;

                Row row1 = sheet.createRow(1);
                Cell cell1 = row1.createCell(0);
                cell1.setCellValue("JUNTA MUNICIPAL DE AGUA POTABLE Y ALCANTARILLADO DE CELAYA.");
                cell1.setCellStyle(titleStyle);
                sheet.addMergedRegion(new CellRangeAddress(1, 1, 0, ultimaCol));

                Row row2 = sheet.createRow(2);
                Cell cell2 = row2.createCell(0);
                cell2.setCellValue("División Del Norte #132, Col. El Vergel, Celaya, Gto. C.P: 38078");
                cell2.setCellStyle(subTitleStyle);
                sheet.addMergedRegion(new CellRangeAddress(2, 2, 0, ultimaCol));


                try (
                        InputStream jmpaLogo = ActDiariaView.class.getClassLoader()
                                .getResourceAsStream("META-INF/resources/images/LOGO_24'27.png");
                        InputStream adminLogo = ActDiariaView.class.getClassLoader()
                                .getResourceAsStream("META-INF/resources/images/LOGO_admon2.png")
                ) {
                    if (jmpaLogo != null || adminLogo != null) {
                        byte[] bytes = IOUtils.toByteArray(jmpaLogo);
                        byte[] bytes1 = IOUtils.toByteArray(adminLogo);
                        int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
                        int pictureIdx1 = workbook.addPicture(bytes1, Workbook.PICTURE_TYPE_PNG);

                        Drawing<?> drawing = sheet.createDrawingPatriarch();
                        CreationHelper helper = workbook.getCreationHelper();
                        CreationHelper helper1 = workbook.getCreationHelper();

                        ClientAnchor anchor = helper.createClientAnchor();
                        ClientAnchor anchor1 = helper1.createClientAnchor();

                        // Posición en la esquina superior izquierda
                        anchor.setCol1(1);
                        anchor.setRow1(1);

                        anchor1.setCol1(10);
                        anchor1.setRow1(1);

                        Picture pict = drawing.createPicture(anchor, pictureIdx);
                        pict.resize(0.30, 0.60); // Ajusta según el tamaño de tu imagen original

                        Picture pict1 = drawing.createPicture(anchor1, pictureIdx1);
                        pict1.resize(0.30, 0.37);
                    } else {
                        log.error("No se encontró el archivo de imagen en la ruta especificada");
                    }
                } catch (Exception e) {
                    log.error("Error al procesar el logo", e);
                }


                CellStyle headerStyle = workbook.createCellStyle();
                Font headerFont = workbook.createFont();
                headerFont.setBold(true);
                headerFont.setColor(IndexedColors.WHITE.getIndex());
                headerStyle.setFont(headerFont);
                headerStyle.setFillForegroundColor(IndexedColors.MAROON.getIndex());
                headerStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
                headerStyle.setAlignment(HorizontalAlignment.CENTER);
                headerStyle.setBorderBottom(BorderStyle.THIN);

                String[] headers = {"ID","Tipo","Tiempo estimado","Fecha creación","Fecha cierre",
                        "Fecha actualización","Situación","Estado","Duración","Autor","Asunto"};

                int rowNum = 6;
                Row headerRow = sheet.createRow(rowNum++);
                for (int i = 0; i < headers.length; i++) {
                    Cell cell = headerRow.createCell(i);
                    cell.setCellValue(headers[i]);
                    cell.setCellStyle(headerStyle);
                }

                DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm:ss");

                for (Ticket ticket : ticketsCerrados) {
                    Row row = sheet.createRow(rowNum++);
                    row.createCell(0).setCellValue(ticket.getId());
                    row.createCell(1).setCellValue(ticket.getType());
                    row.createCell(2).setCellValue(ticket.getEstimatedHrs() + " horas");
                    row.createCell(3).setCellValue(ticket.getDateCreate() != null ? ticket.getDateCreate().format(formatter) : "");
                    row.createCell(4).setCellValue(ticket.getDateClose() != null ? ticket.getDateClose().format(formatter) : "");
                    row.createCell(5).setCellValue(ticket.getUpdateOn() != null ? ticket.getUpdateOn().format(formatter) : "");
                    row.createCell(7).setCellValue(ticket.getStatus());
                    row.createCell(9).setCellValue(ticket.getAuthor() != null ? ticket.getAuthor().getUsername() : "");
                    row.createCell(10).setCellValue(ticket.getSubject());

                    if (ticket.getDateCreateLocal() != null && ticket.getDateCloseLocal() != null) {
                        long dias = ChronoUnit.DAYS.between(ticket.getDateCreateLocal(), ticket.getDateCloseLocal());
                        row.createCell(8).setCellValue(dias + " días");
                    } else {
                        row.createCell(8).setCellValue("");
                    }

                    if (ticket.getEstimatedHrs() != null && ticket.getDateCreateLocal() != null && ticket.getDateCloseLocal() != null) {
                        long horasReales = ChronoUnit.HOURS.between(ticket.getDateCreateLocal(), ticket.getDateCloseLocal());
                        row.createCell(6).setCellValue(horasReales <= ticket.getEstimatedHrs() ? "En tiempo" : "Excedido");
                    } else {
                        row.createCell(6).setCellValue("Sin estimación");
                    }
                }

                for (int i = 0; i < headers.length; i++) {
                    sheet.autoSizeColumn(i);
                }

                ByteArrayOutputStream out = new ByteArrayOutputStream();
                workbook.write(out);
                workbook.close();

                ui.access(() -> {
                    try {
                        StreamResource resource = new StreamResource("rptGeneralDeTicketsMsaAyda.xlsx",
                                () -> new ByteArrayInputStream(out.toByteArray()));

                        StreamRegistration registration = ui.getSession()
                                .getResourceRegistry().registerResource(resource);

                        ui.getPage().executeJs(
                                "window.open('" + registration.getResourceUri().toString() + "','_blank')"
                        );
                    } catch (Exception ex) {
                        log.error("Error al registrar recurso", ex);
                    } finally {
                        loadingDialog.close();
                    }
                });

            } catch (Exception e) {
                log.error("Error exportando tickets", e);
                ui.access(() -> {
                    loadingDialog.close();
                    Notification.show("Error al generar el reporte", 5000, Notification.Position.MIDDLE)
                            .addThemeVariants(NotificationVariant.LUMO_ERROR);
                });
            }
        }).start();
    }


    private void filtrarTickets() {
        grid.getDataProvider().refreshAll();
    }

    private Dialog createLoadingDialog(String mensaje) {
        Dialog dialog = new Dialog();
        dialog.setCloseOnEsc(false);
        dialog.setCloseOnOutsideClick(false);

        VerticalLayout layout = new VerticalLayout();
        layout.setAlignItems(Alignment.CENTER);
        layout.setPadding(true);
        layout.setSpacing(true);

        ProgressBar progressBar = new ProgressBar();
        progressBar.setIndeterminate(true);
        progressBar.setWidth("15rem");

        Span texto = new Span(mensaje);
        texto.getStyle().set("font-weight", "bold");
        texto.getStyle().set("color", "var(--lumo-primary-text-color)");

        layout.add(texto, progressBar);
        dialog.add(layout);

        return dialog;
    }
}
