-- allium: 1
-- bDS Settings and Style Views
-- Scope: UI content area — settings + style editing surfaces
-- Distilled from: SettingsView.tsx, StyleView.tsx

-- Describes the layout and behaviour of the settings and style views.

use "./i18n.allium" as i18n

-- ─── Settings view ────────────────────────────────────────────

value SettingsView {
    search_query: String?               -- filters sections by keyword match
    active_sections: List<String>       -- visible sections after search filter
    project_section: SettingsProjectSection?
    editor_section: SettingsEditorSection?
    categories: List<SettingsCategoryRow>
    ai_section: SettingsAISection?
    publishing_section: SettingsPublishingSection?
    mcp_section: SettingsMCPSection?
}

value SettingsProjectSection {
    project_name: String                -- text input
    project_description: String         -- textarea (3 rows)
    data_path: String                   -- text input + Browse button + Reset button
    public_url: String                  -- url input
    main_language: String               -- select
    blog_languages: List<String>        -- checkboxes (main language disabled)
    default_author: String              -- text input
    max_posts_per_page: Integer         -- number input (1-500, default 50)
    blogmark_category: String           -- select from categories
}

value SettingsEditorSection {
    default_mode: String                -- select: wysiwyg | markdown | preview
    diff_view_style: String             -- select: inline | side-by-side
    wrap_long_lines: Boolean            -- checkbox
    hide_unchanged_regions: Boolean     -- checkbox
}

value SettingsCategoryRow {
    name: String                        -- read-only for protected categories
    title: String                       -- editable
    render_in_lists: Boolean            -- checkbox
    show_titles: Boolean                -- checkbox
    post_template_slug: String?         -- select
    list_template_slug: String?         -- select
    is_protected: Boolean               -- true for: article, aside, page, picture
}

value SettingsAISection {
    anthropic_api_key: String?          -- masked + Change/Save
    mistral_api_key: String?            -- masked + Change/Save
    ollama_enabled: Boolean             -- toggle, shows model capabilities table (tools/vision)
    lm_studio_enabled: Boolean          -- toggle, shows model capabilities table
    offline_mode: Boolean               -- toggle, switches between online and airplane endpoint
    default_model: String?              -- select from active endpoint models
    title_model: String?                -- select
    image_analysis_model: String?       -- select (vision-capable only)
    system_prompt: String               -- textarea (12 rows) + Save + Reset to Default
}

value SettingsPublishingSection {
    ssh_mode: String                    -- select: scp | rsync
    ssh_host: String                    -- text input
    ssh_username: String                -- text input
    ssh_remote_path: String             -- text input
}

value SettingsMCPSection {
    status: String                      -- port number or "Not running"
    agents: List<MCPAgentRow>
}

value MCPAgentRow {
    agent_name: String                  -- Claude Code, Claude Desktop, GitHub Copilot, etc.
    is_installed: Boolean               -- Add/Remove toggle
}

invariant SettingsProtectedCategories {
    -- Protected categories (article, aside, page, picture) cannot be deleted.
    -- Their Remove button is disabled.
}

invariant SettingsMCPAgents {
    -- MCP section has exactly 7 agent rows in this order:
    -- Claude Code, Claude Desktop, GitHub Copilot, Gemini CLI,
    -- OpenCode, Mistral Vibe, OpenAI Codex.
}

config {
    settings_max_posts_per_page: Integer = 500
    settings_default_posts_per_page: Integer = 50
    settings_system_prompt_rows: Integer = 12
}

surface SettingsViewSurface {
    context settings: SettingsView

    exposes:
        settings.search_query
        settings.active_sections

    provides:
        SettingsSearchChanged(query)
        SettingsProjectSaved(project_data)
        SettingsEditorSaved(editor_data)
        SettingsCategoryAdded(category_name)
        SettingsCategoryUpdated(category_row)
        SettingsCategoryRemoved(category_name)
        SettingsCategoriesResetToDefaults()
        SettingsAIApiKeySaved(provider, key)
        SettingsAIModelRefreshRequested(endpoint)
        SettingsAISystemPromptSaved(prompt)
        SettingsAISystemPromptReset()
        SettingsPublishingSaved(publishing_data)
        SettingsPublishingCleared()
        SettingsMCPAgentToggled(agent_name)
        SettingsRebuildRequested(entity_type)
        SettingsRegenerateThumbnailsRequested()
        SettingsOpenDataFolderRequested()
        StyleThemeSelected(theme_name)
        StyleApplyRequested(theme_name)

    @guarantee SearchBar
        -- Search input in header filters sections by keyword match.
        -- "No results" message with clear button when no sections match.

    @guarantee ProjectSection
        -- Section 1: Project Name, Description (textarea 3 rows), Data Path (text + Browse + Reset),
        --   Public URL, Main Language (select), Blog Languages (checkbox grid, main disabled),
        --   Default Author, Max Posts Per Page (number 1-500),
        --   Blogmark Category (select), Blogmark Bookmarklet (copy button), Save button.

    @guarantee BookmarkletCopy
        -- Copy button copies bookmarklet JavaScript to clipboard.
        -- Bookmarklet uses project's publicUrl to construct POST endpoint.

    @guarantee EditorSection
        -- Section 2: Default Editor Mode (select: WYSIWYG/Markdown/Preview),
        --   Diff View Style (select: Inline/Side-by-side),
        --   Wrap Long Lines (checkbox), Hide Unchanged Regions (checkbox).

    @guarantee ContentCategoriesSection
        -- Section 3: Table with columns: Category, Title, Render in Lists,
        --   Show Titles, Post Template, List Template, Remove.
        -- Protected categories (article, aside, page, picture) cannot be deleted.
        -- Add Category: text input + Add button, validates non-empty and unique.
        -- "Reset to Defaults" restores default categories set.

    @guarantee AISection
        -- Section 4: Anthropic API key, Mistral API key (both masked + Change/Save),
        --   Ollama toggle (with model capabilities table: tools/vision),
        --   LM Studio toggle (with capabilities table),
        --   Offline mode toggle (with dedicated model selectors for chat/title/image),
        --   Default model (with catalog info: max output, context window),
        --   Title model, Image analysis model,
        --   System prompt (textarea config.settings_system_prompt_rows rows + Save + Reset).

    @guarantee AIApiKeyValidation
        -- On Save: test API call to endpoint before persisting.
        -- On failure: toast error message, key not saved.
        -- On success: key encrypted via SecureKeyStore, masked display shown.

    @guarantee AIModelRefresh
        -- Refresh Models button per endpoint fetches model list from URL.
        -- Model selector populated from fetched list.
        -- Per-model info: max output tokens, context window (when available).

    @guarantee TechnologySection
        -- Section 5: scripting capabilities are configured at the application level;
        --   this section does not expose implementation-specific runtime choices.
        --   Semantic Similarity toggle.

    @guarantee PublishingSection
        -- Section 6: SSH Mode (scp/rsync), Host, Username, Remote Path.
        --   Save + Clear buttons.

    @guarantee MCPSection
        -- Section 7: Status badge (port or "Not running").
        -- 7 agent rows with Add/Remove toggle each.

    @guarantee DataMaintenanceSection
        -- Section 8: 6 rebuild buttons (Posts from Files, Media from Files,
        --   Scripts from Files, Templates from Files, Links,
        --   Regenerate Missing Thumbnails).
        -- Open Data Folder button.
        -- Each rebuild executes immediately (no confirmation).
        -- Runs as background task with progress in Tasks panel.

    @guarantee CollapsibleSections
        -- All 8 sections are collapsible.
        -- Section visibility respects search filter.
}

-- ─── Settings view actions ──────────────────────────────────

rule SettingsRebuild {
    when: SettingsRebuildRequested(entity_type)
    -- entity_type: posts | media | scripts | templates | links | thumbnails
    -- Executes immediately (no confirmation dialog)
    -- Runs as background task with progress visible in Tasks panel
    -- On completion: wholesale replaces store data for that entity type
    -- Sidebar and editors re-render with fresh data
}

-- ─── Style view ───────────────────────────────────────────────

value StyleView {
    themes: List<StyleTheme>
    selected_theme: String?
    applied_theme: String?
    preview_mode: String                -- auto | light | dark
}

value StyleTheme {
    name: String
    accent_color: String                -- hex
    light_bg_color: String              -- hex
    dark_bg_color: String               -- hex
}

surface StyleViewSurface {
    context style: StyleView

    exposes:
        for t in style.themes:
            t.name
            t.accent_color
            t.light_bg_color
            t.dark_bg_color
        style.selected_theme
        style.applied_theme
        style.preview_mode

    provides:
        StyleThemeSelected(theme_name)
        StyleApplyRequested(style.selected_theme)
            when style.selected_theme != style.applied_theme
        StylePreviewModeChanged(mode)

    @guarantee ThemePicker
        -- Grid of theme buttons (one per Pico CSS theme).
        -- Each button: swatch with 3 colour tones (accent, light bg, dark bg) + theme name.
        -- Selected theme highlighted with aria-pressed.

    @guarantee ControlsRow
        -- Preview Mode dropdown (Auto/Light/Dark).
        -- Apply Theme button, disabled when selected_theme matches applied_theme.

    @guarantee LivePreview
        -- Iframe at 127.0.0.1:4123/__style-preview with theme and mode query params.
        -- Updates live on selection or preview mode change.

    @guarantee PreviewModeLocal
        -- Preview mode dropdown controls iframe query param only.
        -- Does not persist — local UI state only.
}

rule StyleThemeSelect {
    when: StyleThemeSelected(theme_name)
    -- Updates iframe preview immediately (query param change)
    -- Does NOT persist until Apply is clicked
}

rule StyleApplyTheme {
    when: StyleApplyRequested(theme_name)
    -- Persists picoTheme to project metadata (meta/project.json)
    -- See engine_side_effects.allium UpdateProjectMetadataSideEffects
}
