package de.gecheckt.pdf.umbenenner.adapter.in.gui;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.image.Image;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;

/**
 * JavaFX application entry point for the PDF-Umbenenner GUI inbound adapter.
 * <p>
 * The application starts the editor shell in a clean, unloaded state unless Bootstrap
 * has provided a preloaded startup context. The visible editor surface is delegated to
 * {@link GuiConfigurationEditorWorkspace}.
 *
 * <p>The window title is kept in sync with the workspace's dirty state via the
 * {@code titleUpdateListener} hook. The close-request handler is installed through
 * {@link GuiConfigurationEditorWorkspace#installCloseRequestHandler(Stage)} so that
 * unsaved changes are protected when the user tries to close the window.
 *
 * <p>Beim Schließen des Fensters wird die Anwendung in den Windows System-Tray minimiert.
 * Über das Tray-Kontextmenü kann das Fenster wieder geöffnet oder die Anwendung beendet werden.
 */
public class PdfUmbenennerGuiApplication extends Application {

    private static final Logger LOG = LogManager.getLogger(PdfUmbenennerGuiApplication.class);
    private static final double DEFAULT_WIDTH = 1100;
    private static final double DEFAULT_HEIGHT = 800;

    private SystemTrayManager trayManager;

    /**
     * Creates a new instance of the JavaFX application.
     */
    public PdfUmbenennerGuiApplication() {
        // Required by JavaFX runtime for reflective instantiation.
    }

    /**
     * Initializes and shows the primary stage.
     * <p>
     * Lädt die Anwendungs-Icons in allen verfügbaren Größen und setzt sie am Fenster.
     * Wires the workspace title-update listener to the stage title so any dirty-state change
     * causes an immediate window-title refresh. Installs the close-request handler that
     * guards unsaved changes and minimizes the window to the system tray instead of closing.
     *
     * @param primaryStage the primary stage provided by the JavaFX runtime; never {@code null}
     */
    @Override
    public void start(Stage primaryStage) {
        LOG.info("GUI: JavaFX-Oberfläche wird initialisiert.");

        // Anwendungs-Icons laden; JavaFX wählt je nach Kontext automatisch die passende Größe
        primaryStage.getIcons().addAll(
                new Image(getClass().getResourceAsStream("/icons/Icon16.png")),
                new Image(getClass().getResourceAsStream("/icons/Icon32.png")),
                new Image(getClass().getResourceAsStream("/icons/Icon64.png")),
                new Image(getClass().getResourceAsStream("/icons/Icon128.png"))
        );

        GuiStartupContext startupContext = GuiStartupContextHolder.currentOrBlank();
        GuiConfigurationEditorWorkspace workspace = new GuiConfigurationEditorWorkspace(startupContext);

        // Wire the title-update listener so the stage title stays in sync with the dirty state.
        workspace.titleUpdateListener = primaryStage::setTitle;

        // Statuszeile anlegen und mit dem Workspace verdrahten
        GuiStatusBar statusBar = new GuiStatusBar(startupContext.applicationVersion());
        workspace.statusBarStateListener = statusBar::applyEditorState;

        // Statuszeile unterhalb des Workspace-Inhalts einbetten
        BorderPane outerLayout = new BorderPane();
        outerLayout.setCenter(workspace.root());
        outerLayout.setBottom(statusBar.root());

        Scene scene = new Scene(outerLayout, DEFAULT_WIDTH, DEFAULT_HEIGHT);
        primaryStage.setTitle(GuiWindowTitleFormatter.format(workspace.editorState()));
        primaryStage.setScene(scene);

        // Install the close-request handler that protects unsaved changes.
        workspace.installCloseRequestHandler(primaryStage);

        // System-Tray aktivieren: JavaFX-Runtime nicht beenden wenn Fenster versteckt wird
        Platform.setImplicitExit(false);
        trayManager = new SystemTrayManager(primaryStage);
        if (trayManager.install()) {
            installTrayCloseHandler(primaryStage, workspace);
        }

        primaryStage.setMaximized(true);
        primaryStage.show();

        // Versuche, die zuletzt geladene Konfigurationsdatei automatisch zu laden.
        workspace.autoLoadLastConfiguration();

        LOG.info("GUI: Hauptfenster erfolgreich angezeigt.");
    }

    /**
     * Called by the JavaFX runtime when the application is stopping.
     * <p>
     * Entfernt das System-Tray-Icon und loggt das Beenden.
     */
    @Override
    public void stop() {
        LOG.info("GUI: JavaFX-Anwendung wird beendet.");
        if (trayManager != null) {
            trayManager.remove();
        }
    }

    /**
     * Legt einen Close-Request-Handler an, der bei sauberem Zustand das Fenster in den
     * System-Tray minimiert statt es zu schließen.
     * <p>
     * Der vom Workspace installierte Handler wird dabei vorrangig aufgerufen. Nur wenn
     * er das Event nicht konsumiert (sauberer Zustand, keine laufenden Operationen),
     * greift dieser Handler und versteckt das Fenster.
     *
     * @param stage     das primäre Fenster
     * @param workspace der Workspace-Handler, der bereits installiert wurde
     */
    private void installTrayCloseHandler(Stage stage, GuiConfigurationEditorWorkspace workspace) {
        EventHandler<WindowEvent> workspaceHandler = stage.getOnCloseRequest();
        stage.setOnCloseRequest(event -> {
            // Workspace-Handler zuerst: prüft Dirty-State, laufende Operationen usw.
            if (workspaceHandler != null) {
                workspaceHandler.handle(event);
            }
            // Wurde das Event nicht konsumiert, ist der Zustand sauber: Fenster in Tray verstecken
            if (!event.isConsumed()) {
                event.consume();
                LOG.info("GUI: Fenster wird in den System-Tray minimiert.");
                stage.hide();
            }
        });
    }
}
