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

import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.AiProviderFamilyStringConverter;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorState;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiProviderConfigurationState;
import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.Label;
import javafx.scene.control.Separator;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.Region;

/**
 * Permanente Statuszeile am unteren Rand des Hauptfensters.
 * <p>
 * Die Statuszeile zeigt immer drei Segmente:
 * <ul>
 *   <li><b>Links:</b> Anwendungsversion im Format {@code V<version>}, z.&nbsp;B. {@code Vdev}.</li>
 *   <li><b>Mitte:</b> Aktiver Provider und Modellname aus der geladenen Konfiguration.</li>
 *   <li><b>Rechts:</b> Pfad der geladenen Konfigurationsdatei.</li>
 * </ul>
 * Wenn keine Konfiguration geladen ist, zeigen Mitte und Rechts den Text
 * {@value #KEIN_PROFIL_TEXT}. Die Versionsanzeige ist stets sichtbar.
 * <p>
 * Alle Aktualisierungen dieser Komponente müssen auf dem JavaFX Application Thread erfolgen.
 * Die Klasse selbst erzwingt dies nicht; der Aufrufer trägt die Verantwortung.
 */
public final class GuiStatusBar {
    private static final String LABEL_STYLE = "-fx-font-size: 11px; -fx-text-fill: #555555;";



    /** Anzeigetext wenn keine Konfiguration geladen ist. */
    static final String KEIN_PROFIL_TEXT = "Kein Profil geladen";

    /** Präfix vor der Versionsnummer in der linken Statuszeilen-Zelle. */
    private static final String VERSION_PREFIX = "V";

    private static final AiProviderFamilyStringConverter PROVIDER_CONVERTER =
            new AiProviderFamilyStringConverter();

    private final String applicationVersion;
    private final BorderPane root;
    private final Label versionLabel;
    private final Label providerLabel;
    private final Label configPathLabel;

    /**
     * Erstellt eine neue Statuszeile mit der angegebenen Anwendungsversion.
     *
     * @param applicationVersion die aufgelöste Versionsnummer; {@code null} oder leer führt zum
     *                           Fallback {@code "dev"}
     */
    public GuiStatusBar(String applicationVersion) {
        this.applicationVersion = (applicationVersion == null || applicationVersion.isBlank())
                ? "dev"
                : applicationVersion;

        // Linkes Segment: Versionsanzeige
        this.versionLabel = new Label(VERSION_PREFIX + this.applicationVersion);
        this.versionLabel.setStyle(LABEL_STYLE);

        // Mittleres Segment: Provider und Modell
        this.providerLabel = new Label(KEIN_PROFIL_TEXT);
        this.providerLabel.setStyle(LABEL_STYLE);
        this.providerLabel.setAlignment(Pos.CENTER);

        // Rechtes Segment: Konfigurationspfad
        this.configPathLabel = new Label(KEIN_PROFIL_TEXT);
        this.configPathLabel.setStyle(LABEL_STYLE);
        this.configPathLabel.setAlignment(Pos.CENTER_RIGHT);

        // Abstandhalter zwischen den Segmenten
        Region leftSpacer = new Region();
        Region rightSpacer = new Region();
        HBox.setHgrow(leftSpacer, Priority.ALWAYS);
        HBox.setHgrow(rightSpacer, Priority.ALWAYS);

        HBox content = new HBox(16,
                versionLabel, leftSpacer,
                providerLabel, rightSpacer,
                configPathLabel);
        content.setAlignment(Pos.CENTER_LEFT);
        content.setPadding(new Insets(4, 12, 4, 12));
        content.setStyle("-fx-background-color: #f5f5f5;");

        Separator topSeparator = new Separator();

        this.root = new BorderPane();
        this.root.setTop(topSeparator);
        this.root.setCenter(content);
    }

    /**
     * Gibt den Wurzelknoten der Statuszeile zurück, der in das Hauptfenster eingebettet wird.
     *
     * @return der Wurzelknoten; nie {@code null}
     */
    public BorderPane root() {
        return root;
    }

    /**
     * Aktualisiert die Statuszeile anhand des aktuellen Editor-Zustands.
     * <p>
     * Ist kein Dateisnapshot vorhanden, wird {@link #clearConfiguration()} ausgeführt.
     * Andernfalls werden Provider, Modell und Konfigurationspfad aus dem Zustand ermittelt
     * und angezeigt.
     * <p>
     * Muss auf dem JavaFX Application Thread aufgerufen werden.
     *
     * @param state der aktuelle Editor-Zustand; darf nicht {@code null} sein
     */
    public void applyEditorState(GuiConfigurationEditorState state) {
        if (state == null || !state.hasLoadedFileSnapshot()) {
            clearConfiguration();
            return;
        }
        String configPath = state.configurationPathText();
        String providerText = resolveProviderText(state);
        providerLabel.setText(providerText);
        configPathLabel.setText(configPath.isBlank() ? KEIN_PROFIL_TEXT : configPath);
    }

    /**
     * Setzt Mitte und Rechts der Statuszeile auf den Text {@link #KEIN_PROFIL_TEXT} zurück.
     * <p>
     * Die Versionsanzeige bleibt unverändert.
     * <p>
     * Muss auf dem JavaFX Application Thread aufgerufen werden.
     */
    public void clearConfiguration() {
        providerLabel.setText(KEIN_PROFIL_TEXT);
        configPathLabel.setText(KEIN_PROFIL_TEXT);
    }

    /**
     * Gibt den aktuell angezeigten Versionstext zurück (inkl. Präfix {@code V}).
     * <p>
     * Für Tests zugänglich.
     *
     * @return der angezeigte Versionstext; nie {@code null}
     */
    String versionText() {
        return versionLabel.getText();
    }

    /**
     * Gibt den aktuell angezeigten Provider-Text zurück.
     * <p>
     * Für Tests zugänglich.
     *
     * @return der angezeigte Provider-Text; nie {@code null}
     */
    String providerText() {
        return providerLabel.getText();
    }

    /**
     * Gibt den aktuell angezeigten Konfigurationspfad-Text zurück.
     * <p>
     * Für Tests zugänglich.
     *
     * @return der angezeigte Konfigurationspfad-Text; nie {@code null}
     */
    String configPathText() {
        return configPathLabel.getText();
    }

    /**
     * Ermittelt den anzuzeigenden Provider-Text aus dem Editor-Zustand.
     * <p>
     * Das Format ist: {@code Provider: <AnzeigeName> · <Modellname>}, wobei der Modellname
     * weggelassen wird, wenn er leer ist.
     *
     * @param state der Editor-Zustand; darf nicht {@code null} sein
     * @return der formatierte Provider-Text; nie {@code null}
     */
    private static String resolveProviderText(GuiConfigurationEditorState state) {
        String activeIdentifier = state.values().activeProviderFamily();
        if (activeIdentifier == null || activeIdentifier.isBlank()) {
            return KEIN_PROFIL_TEXT;
        }
        AiProviderFamily family = AiProviderFamily.fromIdentifier(activeIdentifier).orElse(null);
        if (family == null) {
            return KEIN_PROFIL_TEXT;
        }
        String displayName = PROVIDER_CONVERTER.toString(family);
        GuiProviderConfigurationState providerState = state.values().providerConfiguration(family);
        String model = providerState != null ? providerState.model() : "";
        if (model == null || model.isBlank()) {
            return "Provider: " + displayName;
        }
        return "Provider: " + displayName + " · " + model;
    }
}
