package de.assecutor.votianlt.pages.view;

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.dialog.Dialog;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.component.html.Div;
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.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.server.StreamResource;
import com.vaadin.flow.router.HasDynamicTitle;
import com.vaadin.flow.router.Route;
import de.assecutor.votianlt.model.Job;
import de.assecutor.votianlt.model.JobStatus;
import de.assecutor.votianlt.messaging.MessagingPublisher;
import de.assecutor.votianlt.pages.base.ui.component.DialogStylingHelper;
import de.assecutor.votianlt.pages.base.ui.component.ViewToolbar;
import de.assecutor.votianlt.util.DateTimeFormatUtil;
import de.assecutor.votianlt.repository.CustomerInvoiceRepository;
import de.assecutor.votianlt.repository.JobRepository;
import de.assecutor.votianlt.security.SecurityService;
import de.assecutor.votianlt.service.ClientConnectionService;
import de.assecutor.votianlt.service.JobHistoryService;
import jakarta.annotation.security.RolesAllowed;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.time.LocalDateTime;
import java.util.Map;

@Route(value = "jobs", layout = de.assecutor.votianlt.pages.base.ui.view.MainLayout.class)
@RolesAllowed({ "USER" })
@Slf4j
public class ShowJobsView extends VerticalLayout implements HasDynamicTitle {

    private final DatePicker startDate = new DatePicker();
    private final DatePicker endDate = new DatePicker();
    private final TextField searchField = new TextField();
    private final ComboBox<String> statusFilter = new ComboBox<>();
    private final JobRepository jobRepository;
    private final JobHistoryService jobHistoryService;
    private final SecurityService securityService;
    private final ClientConnectionService clientConnectionService;
    private final MessagingPublisher messagingPublisher;
    private final Grid<Job> grid = new Grid<>(Job.class, false);

    @Autowired
    public ShowJobsView(JobRepository jobRepository, JobHistoryService jobHistoryService,
            SecurityService securityService, ClientConnectionService clientConnectionService,
            MessagingPublisher messagingPublisher, CustomerInvoiceRepository customerInvoiceRepository) {
        this.jobRepository = jobRepository;
        this.jobHistoryService = jobHistoryService;
        this.securityService = securityService;
        this.clientConnectionService = clientConnectionService;
        this.messagingPublisher = messagingPublisher;
        setSizeFull();
        setPadding(true);
        setSpacing(true);
        addClassName("data-view");

        startDate.setLabel(getTranslation("jobs.filter.startdate"));
        endDate.setLabel(getTranslation("jobs.filter.enddate"));
        searchField.setLabel(getTranslation("jobs.filter.search"));
        statusFilter.setLabel(getTranslation("jobs.filter.status"));
        Button exportButton = new Button(getTranslation("jobs.button.csvexport"));
        exportButton.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
        ViewToolbar toolbar = new ViewToolbar(getTranslation("nav.jobs"), exportButton);
        add(toolbar);

        // Configure status filter
        statusFilter.setItems(getTranslation("jobs.status.all"), getTranslation("jobs.status.open"),
                getTranslation("jobs.status.done"));
        statusFilter.setValue(getTranslation("jobs.status.open"));

        // Configure search field
        searchField.setPlaceholder(getTranslation("jobs.filter.search.placeholder"));
        searchField.setClearButtonVisible(true);

        // Filterleiste mit Export-Button am rechten Rand
        Button applyFilter = new Button(getTranslation("jobs.filter.apply"));
        applyFilter.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        HorizontalLayout leftFilters = new HorizontalLayout(startDate, endDate, searchField, statusFilter, applyFilter);
        leftFilters.setAlignItems(Alignment.END);
        leftFilters.getStyle().set("flex-wrap", "wrap");

        HorizontalLayout filterBar = new HorizontalLayout();
        filterBar.setWidthFull();
        filterBar.add(leftFilters);
        filterBar.add(exportButton);
        filterBar.setJustifyContentMode(JustifyContentMode.BETWEEN);
        filterBar.setAlignItems(Alignment.END);
        filterBar.getStyle().set("flex-wrap", "wrap");
        filterBar.addClassNames("surface-panel", "filter-panel");
        add(filterBar);

        // Init default period: last 30 days
        java.time.LocalDate today = java.time.LocalDate.now();
        startDate.setValue(today.minusDays(30));
        endDate.setValue(today);
        applyFilter.addClickListener(e -> loadData());
        exportButton.addClickListener(e -> exportToCsv());

        // Add real-time filtering
        searchField.addValueChangeListener(e -> loadData());
        statusFilter.addValueChangeListener(e -> loadData());
        startDate.addValueChangeListener(e -> loadData());
        endDate.addValueChangeListener(e -> loadData());

        // Configure grid columns: Auftraggeber, Auftragsnummer, Auftragsdatum, Zielort
        grid.addColumn(job -> extractCompanyName(job.getCustomerSelection()))
                .setHeader(getTranslation("jobs.column.customer")).setAutoWidth(true).setFlexGrow(1).setSortable(true);
        grid.addColumn(Job::getJobNumber).setHeader(getTranslation("jobs.column.jobnumber")).setAutoWidth(true)
                .setSortable(true);
        grid.addColumn(job -> DateTimeFormatUtil.formatDateTime(job.getCreatedAt()))
                .setHeader(getTranslation("jobs.column.jobdate")).setAutoWidth(true).setSortable(true);
        grid.addColumn(Job::getFirstDeliveryCity).setHeader(getTranslation("jobs.column.destination"))
                .setAutoWidth(true).setFlexGrow(1).setSortable(true);

        // Action column: manual completion for jobs without digital processing
        grid.addComponentColumn(job -> {
            if (!job.isDigitalProcessing() && job.getStatus() != JobStatus.COMPLETED
                    && job.getStatus() != JobStatus.CANCELLED) {
                Button completeBtn = new Button(new Icon(VaadinIcon.CHECK_CIRCLE));
                completeBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_SUCCESS);
                completeBtn.setTooltipText(getTranslation("jobs.tooltip.complete"));
                completeBtn.addClickListener(e -> {
                    e.getSource().getElement().getNode(); // prevent row click
                    showCompleteJobDialog(job);
                });
                return completeBtn;
            }
            return new com.vaadin.flow.component.html.Span();
        }).setHeader("").setAutoWidth(true).setFlexGrow(0);

        // Invoice column - only show for completed jobs
        grid.addComponentColumn(job -> {
            if (job.getStatus() == JobStatus.COMPLETED) {
                if (hasInvoice(job)) {
                    Button invoiceBtn = new Button(new Icon(VaadinIcon.FILE_TEXT_O));
                    invoiceBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY);
                    invoiceBtn.setTooltipText(getTranslation("jobs.tooltip.showinvoice"));
                    invoiceBtn.addClickListener(e -> {
                        e.getSource().getElement().getNode();
                        customerInvoiceRepository.findById(job.getInvoiceId()).ifPresentOrElse(invoice -> {
                            if (invoice.getPdfData() != null) {
                                CreateInvoiceView.showSavedInvoiceDialog(invoice.getPdfData(),
                                        invoice.getInvoiceNumber(), this);
                            } else {
                                getUI().ifPresent(ui -> ui.navigate("create_invoice/" + job.getId().toHexString()));
                            }
                        }, () -> getUI().ifPresent(ui -> ui.navigate("create_invoice/" + job.getId().toHexString())));
                    });
                    return invoiceBtn;
                }

                Button createInvoiceBtn = new Button(new Icon(VaadinIcon.DOLLAR));
                createInvoiceBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_SUCCESS);
                createInvoiceBtn.setTooltipText(getTranslation("jobs.tooltip.createinvoice"));
                createInvoiceBtn.addClickListener(e -> {
                    e.getSource().getElement().getNode();
                    getUI().ifPresent(ui -> ui.navigate("create_invoice/" + job.getId().toHexString()));
                });
                return createInvoiceBtn;
            }
            return new com.vaadin.flow.component.html.Span();
        }).setHeader("").setWidth("60px").setFlexGrow(0);

        // Delete column (last column, right side)
        grid.addComponentColumn(job -> {
            if (job.getStatus() == JobStatus.COMPLETED || job.getStatus() == JobStatus.CANCELLED
                    || job.getStatus() == JobStatus.DELIVERED) {
                return new com.vaadin.flow.component.html.Span(); // No delete button for completed jobs
            }
            Button deleteBtn = new Button(new Icon(VaadinIcon.TRASH));
            deleteBtn.addThemeVariants(ButtonVariant.LUMO_TERTIARY, ButtonVariant.LUMO_ERROR);
            deleteBtn.setTooltipText(getTranslation("jobs.tooltip.delete"));
            deleteBtn.addClickListener(e -> {
                e.getSource().getElement().getNode(); // prevent row click
                showDeleteJobDialog(job);
            });
            return deleteBtn;
        }).setHeader("").setWidth("60px").setFlexGrow(0);

        grid.setMultiSort(true);
        grid.setSizeFull();
        grid.addClassName("data-grid");

        // Make grid rows clickable
        grid.setSelectionMode(Grid.SelectionMode.SINGLE);
        grid.getStyle().set("cursor", "pointer");

        // Add click listener to navigate to job summary view
        grid.addItemClickListener(event -> {
            Job job = event.getItem();
            if (job != null && job.getId() != null) {
                getUI().ifPresent(ui -> ui.navigate("job_summary/" + job.getId().toHexString()));
            }
        });

        Div gridPanel = new Div(grid);
        gridPanel.addClassNames("surface-panel", "data-grid-panel");
        gridPanel.setSizeFull();

        add(gridPanel);

        loadData();
    }

    private void showCompleteJobDialog(Job job) {
        Dialog dialog = DialogStylingHelper.createConfirmationDialog(
                getTranslation("jobs.dialog.complete.title"),
                getTranslation("jobs.dialog.complete.text", job.getJobNumber()),
                "560px",
                getTranslation("button.cancel"),
                getTranslation("jobs.dialog.complete.confirm"),
                () -> {
                    try {
                        JobStatus oldStatus = job.getStatus();
                        job.setStatus(JobStatus.COMPLETED);
                        job.setUpdatedAt(LocalDateTime.now());
                        jobRepository.save(job);
                        jobHistoryService.logStatusChange(job, oldStatus, JobStatus.COMPLETED, "Manuell");
                        Notification.show(getTranslation("jobs.notification.completed", job.getJobNumber()), 3000,
                                Notification.Position.BOTTOM_END).addThemeVariants(NotificationVariant.LUMO_SUCCESS);
                        loadData();
                    } catch (Exception ex) {
                        Notification.show(getTranslation("jobs.notification.complete.error", ex.getMessage()), 5000,
                                Notification.Position.BOTTOM_END).addThemeVariants(NotificationVariant.LUMO_ERROR);
                    }
                },
                ButtonVariant.LUMO_PRIMARY);
        dialog.open();
    }

    private void showDeleteJobDialog(Job job) {
        Dialog dialog = DialogStylingHelper.createConfirmationDialog(
                getTranslation("jobs.dialog.delete.title"),
                getTranslation("jobs.dialog.delete.text", job.getJobNumber()),
                "560px",
                getTranslation("button.cancel"),
                getTranslation("button.delete"),
                () -> {
                    try {
                        // Notify client before deleting if online
                        notifyClientJobDeleted(job);

                        jobRepository.delete(job);
                        Notification.show(getTranslation("jobs.notification.deleted", job.getJobNumber()), 3000,
                                Notification.Position.BOTTOM_END).addThemeVariants(NotificationVariant.LUMO_SUCCESS);
                        loadData();
                    } catch (Exception ex) {
                        Notification.show(getTranslation("jobs.notification.delete.error", ex.getMessage()), 5000,
                                Notification.Position.BOTTOM_END).addThemeVariants(NotificationVariant.LUMO_ERROR);
                    }
                },
                ButtonVariant.LUMO_PRIMARY,
                ButtonVariant.LUMO_ERROR);
        dialog.open();
    }

    private void notifyClientJobDeleted(Job job) {
        if (!job.isDigitalProcessing()) {
            return;
        }

        String appUserId = job.getAppUser();
        if (appUserId == null || appUserId.isBlank()) {
            return;
        }

        if (!clientConnectionService.isClientConnected(appUserId)) {
            log.info("[JOB] Client {} not online, skipping job_deleted notification", appUserId);
            return;
        }

        Map<String, Object> payload = Map.of("type", "job_deleted", "jobId", job.getId().toHexString(), "jobNumber",
                job.getJobNumber() != null ? job.getJobNumber() : "", "deletedAt", LocalDateTime.now().toString());

        log.info("[JOB] Sending job_deleted to {}: {}", appUserId, payload);
        messagingPublisher.publishAsJson(appUserId, "job_deleted", payload);
    }

    private void loadData() {
        var start = startDate.getValue();
        var end = endDate.getValue();
        java.time.LocalDateTime startDt = start != null ? start.atStartOfDay()
                : java.time.LocalDate.now().minusDays(30).atStartOfDay();
        java.time.LocalDateTime endDt = end != null ? end.atTime(23, 59, 59)
                : java.time.LocalDate.now().atTime(23, 59, 59);

        // Status-Filter bestimmen
        String selectedStatus = statusFilter.getValue();
        java.util.List<JobStatus> statusList;

        if (getTranslation("jobs.status.done").equals(selectedStatus)) {
            statusList = java.util.List.of(JobStatus.DELIVERED, JobStatus.COMPLETED, JobStatus.CANCELLED);
        } else if (getTranslation("jobs.status.open").equals(selectedStatus)) {
            statusList = java.util.List.of(JobStatus.CREATED, JobStatus.IN_PROGRESS, JobStatus.PICKUP_SCHEDULED,
                    JobStatus.PICKED_UP, JobStatus.IN_TRANSIT);
        } else { // "Alle"
            statusList = java.util.Arrays.asList(JobStatus.values());
        }

        // Suchtext für Auftragsnummer
        String searchText = searchField.getValue();
        String jobNumberPattern = searchText != null && !searchText.trim().isEmpty() ? searchText.trim() : ".*"; // Regex
                                                                                                                 // für
                                                                                                                 // alle
                                                                                                                 // wenn
                                                                                                                 // leer

        // Verwende die erweiterte Suchmethode, gefiltert nach aktuellem Benutzer
        String currentUserId = securityService.getCurrentUserId().toHexString();
        var filteredJobs = jobRepository.findWithFiltersByCreatedBy(currentUserId, startDt, endDt, jobNumberPattern,
                statusList);
        grid.setItems(filteredJobs);
    }

    private void exportToCsv() {
        var items = grid.getListDataView().getItems().toList();

        StreamResource resource = new StreamResource("jobs.csv", () -> new java.io.ByteArrayInputStream(
                generateCsv(items).getBytes(java.nio.charset.StandardCharsets.UTF_8)));
        resource.setContentType("text/csv");
        resource.setCacheTime(0);

        // Create download anchor and trigger immediately
        Anchor downloadAnchor = new Anchor(resource, "Download CSV");
        downloadAnchor.getElement().setAttribute("download", "jobs.csv");
        downloadAnchor.setTarget("_blank");

        // Add to UI and trigger download via JavaScript
        add(downloadAnchor);
        getUI().ifPresent(ui -> ui.getPage().executeJs(
                "const link = arguments[0]; link.click(); setTimeout(() => link.remove(), 100);",
                downloadAnchor.getElement()));
    }

    private String generateCsv(java.util.List<Job> jobs) {
        StringBuilder csv = new StringBuilder();
        // CSV Header
        csv.append(getTranslation("csv.header.customer")).append(",").append(getTranslation("csv.header.jobnumber"))
                .append(",").append(getTranslation("csv.header.jobdate")).append(",")
                .append(getTranslation("csv.header.destination")).append("\n");

        // CSV Data
        for (Job job : jobs) {
            csv.append(escapeCsv(extractCompanyName(job.getCustomerSelection()))).append(",");
            csv.append(escapeCsv(job.getJobNumber())).append(",");
            csv.append(DateTimeFormatUtil.formatDateTime(job.getCreatedAt())).append(",");
            csv.append(escapeCsv(job.getDeliveryCitiesDisplay())).append("\n");
        }

        return csv.toString();
    }

    private String escapeCsv(String value) {
        if (value == null)
            return "";
        if (value.contains(",") || value.contains("\"") || value.contains("\n")) {
            return "\"" + value.replace("\"", "\"\"") + "\"";
        }
        return value;
    }

    private boolean hasInvoice(Job job) {
        return job.getInvoiceId() != null && !job.getInvoiceId().isBlank();
    }

    private String extractCompanyName(String customerSelection) {
        if (customerSelection == null || customerSelection.isBlank()) {
            return "";
        }
        // Format: "Firmenname | Vorname Nachname" - extrahiere nur den Firmennamen
        int separatorIndex = customerSelection.indexOf(" | ");
        if (separatorIndex > 0) {
            return customerSelection.substring(0, separatorIndex).trim();
        }
        return customerSelection.trim();
    }

    @Override
    public String getPageTitle() {
        return getTranslation("page.title.jobs");
    }
}
