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

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.nio.file.Path;
import java.util.Properties;

import org.junit.jupiter.api.Test;

import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationEditorState;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationFileSnapshot;
import de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationTemplateFactory;

/**
 * Unit tests for {@link GuiWindowTitleFormatter}.
 */
class GuiWindowTitleFormatterTest {

    // =========================================================================
    // Clean state — no file loaded (new configuration)
    // =========================================================================

    @Test
    void format_cleanStateWithoutFile_returnsBaseTitle() {
        GuiConfigurationEditorState state = GuiConfigurationTemplateFactory.createStandardTemplate();
        // Standard template is clean and has no loaded file snapshot.
        assertFalse(state.isDirty(), "Precondition: template state must be clean");
        assertTrue(state.isNewConfiguration(), "Precondition: no file snapshot");

        String title = GuiWindowTitleFormatter.format(state);

        assertEquals(
                GuiWindowTitleFormatter.APPLICATION_NAME
                        + GuiWindowTitleFormatter.SEPARATOR
                        + GuiWindowTitleFormatter.NEW_CONFIGURATION_LABEL,
                title,
                "Clean new-configuration state must use the new-configuration label without dirty prefix");
        assertFalse(title.startsWith(GuiWindowTitleFormatter.DIRTY_PREFIX),
                "Clean state must not carry the dirty prefix");
    }

    // =========================================================================
    // Clean state — file loaded
    // =========================================================================

    @Test
    void format_cleanStateWithFile_showsFilename() {
        GuiConfigurationEditorState template = GuiConfigurationTemplateFactory.createStandardTemplate();
        Path filePath = Path.of("config", "application.properties");
        GuiConfigurationFileSnapshot snapshot = new GuiConfigurationFileSnapshot(filePath, new Properties());
        GuiConfigurationEditorState state = template.withLoadedFileSnapshot(snapshot);

        assertFalse(state.isDirty(), "Precondition: loaded state must be clean");

        String title = GuiWindowTitleFormatter.format(state);

        assertEquals(
                GuiWindowTitleFormatter.APPLICATION_NAME
                        + GuiWindowTitleFormatter.SEPARATOR
                        + "application.properties",
                title,
                "Clean loaded state must show only the filename without path segments");
        assertFalse(title.startsWith(GuiWindowTitleFormatter.DIRTY_PREFIX));
    }

    // =========================================================================
    // Dirty state — no file loaded
    // =========================================================================

    @Test
    void format_dirtyStateWithoutFile_addsDirtyPrefix() {
        GuiConfigurationEditorState template = GuiConfigurationTemplateFactory.createStandardTemplate();
        // Modify values to make it dirty.
        GuiConfigurationEditorState dirty = template.withValues(
                modifiedSourceFolder(template, "changed-source"));

        assertTrue(dirty.isDirty(), "Precondition: state must be dirty");
        assertTrue(dirty.isNewConfiguration(), "Precondition: no file snapshot");

        String title = GuiWindowTitleFormatter.format(dirty);

        assertTrue(title.startsWith(GuiWindowTitleFormatter.DIRTY_PREFIX),
                "Dirty state must carry the leading dirty prefix");
        assertTrue(title.contains(GuiWindowTitleFormatter.NEW_CONFIGURATION_LABEL),
                "Dirty new-configuration title must still include the new-configuration label");
    }

    // =========================================================================
    // Dirty state — file loaded
    // =========================================================================

    @Test
    void format_dirtyStateWithFile_addsDirtyPrefixAndShowsFilename() {
        GuiConfigurationEditorState template = GuiConfigurationTemplateFactory.createStandardTemplate();
        Path filePath = Path.of("config", "myconfig.properties");
        GuiConfigurationFileSnapshot snapshot = new GuiConfigurationFileSnapshot(filePath, new Properties());
        GuiConfigurationEditorState loaded = template.withLoadedFileSnapshot(snapshot);

        // Make it dirty by changing values.
        GuiConfigurationEditorState dirty = loaded.withValues(
                modifiedSourceFolder(loaded, "new-source"));

        assertTrue(dirty.isDirty(), "Precondition: state must be dirty");

        String title = GuiWindowTitleFormatter.format(dirty);

        assertTrue(title.startsWith(GuiWindowTitleFormatter.DIRTY_PREFIX),
                "Dirty loaded state must carry the leading dirty prefix");
        assertTrue(title.contains("myconfig.properties"),
                "Dirty loaded state title must include the filename");
    }

    // =========================================================================
    // After markClean — dirty prefix removed
    // =========================================================================

    @Test
    void format_afterMarkClean_removesPrefix() {
        GuiConfigurationEditorState template = GuiConfigurationTemplateFactory.createStandardTemplate();
        GuiConfigurationEditorState dirty = template.withValues(
                modifiedSourceFolder(template, "changed"));
        assertTrue(dirty.isDirty(), "Precondition: must be dirty before clean");

        GuiConfigurationEditorState clean = dirty.markClean();
        assertFalse(clean.isDirty(), "Precondition: must be clean after markClean");

        String title = GuiWindowTitleFormatter.format(clean);

        assertFalse(title.startsWith(GuiWindowTitleFormatter.DIRTY_PREFIX),
                "After markClean the title must no longer carry the dirty prefix");
    }

    // =========================================================================
    // Application name constant is always present
    // =========================================================================

    @Test
    void format_alwaysContainsApplicationName() {
        GuiConfigurationEditorState blank = GuiConfigurationTemplateFactory.createBlankStartState();
        String title = GuiWindowTitleFormatter.format(blank);

        assertTrue(title.contains(GuiWindowTitleFormatter.APPLICATION_NAME),
                "Every title variant must include the application name");
    }

    // =========================================================================
    // Helpers
    // =========================================================================

    /**
     * Creates a copy of the supplied state's {@code values} with a different source folder.
     */
    private static de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationValues
            modifiedSourceFolder(GuiConfigurationEditorState state, String newSourceFolder) {
        de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationValues v = state.values();
        return new de.gecheckt.pdf.umbenenner.adapter.in.gui.editor.GuiConfigurationValues(
                newSourceFolder,
                v.targetFolder(),
                v.sqliteFile(),
                v.promptTemplateFile(),
                v.runtimeLockFile(),
                v.logDirectory(),
                v.logLevel(),
                v.maxRetriesTransient(),
                v.maxPages(),
                v.maxTextCharacters(),
                v.maxTitleLength(),
                v.logAiSensitive(),
                v.activeProviderFamily(),
                v.providerConfigurations());
    }
}
