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

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

import java.util.List;

import org.junit.jupiter.api.Test;

import de.gecheckt.pdf.umbenenner.application.config.provider.AiProviderFamily;

class GuiConfigurationTemplateFactoryTest {

    @Test
    void createStandardTemplate_providesCompleteCleanEditorState() {
        GuiConfigurationEditorState state = GuiConfigurationTemplateFactory.createStandardTemplate();

        assertFalse(state.isDirty());
        assertFalse(state.hasLoadedFileSnapshot());
        assertTrue(state.isNewConfiguration());
        assertFalse(state.hasPendingMigrationMessage());

        GuiConfigurationValues values = state.values();
        assertEquals("./work/local/source", values.sourceFolder());
        assertEquals("./work/local/target", values.targetFolder());
        assertEquals("./work/local/pdf-umbenenner.db", values.sqliteFile());
        assertEquals("./config/prompts/template.txt", values.promptTemplateFile());
        assertEquals("./work/local/pdf-umbenenner.lock", values.runtimeLockFile());
        assertEquals("./work/local/logs", values.logDirectory());
        assertEquals("INFO", values.logLevel());
        assertEquals("3", values.maxRetriesTransient());
        assertEquals("10", values.maxPages());
        assertEquals("1000", values.maxTextCharacters());
        assertEquals("60", values.maxTitleLength());
        assertEquals("false", values.logAiSensitive());
        assertEquals(AiProviderFamily.CLAUDE.getIdentifier(), values.activeProviderFamily());

        List<AiProviderFamily> providerOrder = values.providerConfigurations().keySet().stream().toList();
        assertEquals(List.of(AiProviderFamily.CLAUDE, AiProviderFamily.OPENAI_COMPATIBLE), providerOrder);

        GuiProviderConfigurationState claude = values.providerConfiguration(AiProviderFamily.CLAUDE);
        assertNotNull(claude);
        assertEquals("https://api.anthropic.com", claude.baseUrl());
        assertEquals("claude-3-5-sonnet-20241022", claude.model());
        assertEquals("60", claude.timeoutSeconds());
        assertEquals("", claude.apiKey().propertyValue());
        assertEquals(GuiValueOrigin.UNKNOWN, claude.apiKey().effectiveValueOrigin());

        GuiProviderConfigurationState openAi = values.providerConfiguration(AiProviderFamily.OPENAI_COMPATIBLE);
        assertNotNull(openAi);
        assertEquals("https://api.openai.com/v1", openAi.baseUrl());
        assertEquals("gpt-4o-mini", openAi.model());
        assertEquals("30", openAi.timeoutSeconds());
        assertEquals("", openAi.apiKey().propertyValue());
        assertEquals(GuiValueOrigin.UNKNOWN, openAi.apiKey().effectiveValueOrigin());
    }

    @Test
    void createBlankStartState_returnsStandardTemplateValuesWithoutLoadedFile() {
        GuiConfigurationEditorState state = GuiConfigurationTemplateFactory.createBlankStartState();

        assertFalse(state.isDirty());
        assertFalse(state.hasLoadedFileSnapshot());
        assertTrue(state.isNewConfiguration());
        assertEquals("", state.configurationPathText());

        GuiConfigurationValues values = state.values();
        assertEquals("./work/local/source", values.sourceFolder());
        assertEquals("./work/local/target", values.targetFolder());
        assertEquals("60", values.maxTitleLength(),
                "Standard template must supply the default title-length value");
        assertEquals(AiProviderFamily.CLAUDE.getIdentifier(), values.activeProviderFamily());
        assertFalse(values.providerConfigurations().isEmpty());
    }

    @Test
    void createEmptyStartState_startsWithoutLoadedConfigurationAndWithoutTemplateValues() {
        GuiConfigurationEditorState state = GuiConfigurationTemplateFactory.createEmptyStartState();

        assertFalse(state.isDirty());
        assertFalse(state.hasLoadedFileSnapshot());
        assertTrue(state.isNewConfiguration());
        assertEquals("", state.configurationPathText());

        GuiConfigurationValues values = state.values();
        assertEquals("", values.sourceFolder());
        assertEquals("", values.targetFolder());
        assertEquals("", values.sqliteFile());
        assertEquals("", values.promptTemplateFile());
        assertEquals("", values.runtimeLockFile());
        assertEquals("", values.logDirectory());
        assertEquals("", values.logLevel());
        assertEquals("", values.maxRetriesTransient());
        assertEquals("", values.maxPages());
        assertEquals("", values.maxTextCharacters());
        assertEquals("", values.maxTitleLength());
        assertEquals("", values.logAiSensitive());
        assertEquals("", values.activeProviderFamily());
        assertTrue(values.providerConfigurations().isEmpty());
    }

    @Test
    void providerConfigurationMap_isImmutableFromOutside() {
        GuiConfigurationValues values = GuiConfigurationTemplateFactory.createStandardValues();

        assertThrows(UnsupportedOperationException.class, () ->
                values.providerConfigurations().put(AiProviderFamily.CLAUDE, GuiProviderConfigurationState.blank()));
    }

    @Test
    void withActiveProviderFamily_reusesProviderBlocksAndChangesSelection() {
        GuiConfigurationValues values = GuiConfigurationTemplateFactory.createStandardValues();

        GuiConfigurationValues switched = values.withActiveProviderFamily(AiProviderFamily.OPENAI_COMPATIBLE.getIdentifier());

        assertEquals(AiProviderFamily.OPENAI_COMPATIBLE.getIdentifier(), switched.activeProviderFamily());
        assertEquals(values.providerConfigurations(), switched.providerConfigurations());
        assertEquals(values.sourceFolder(), switched.sourceFolder());
    }
}
