//
//  HelpView.swift
//  Confab
//
//  Help and commands reference with expandable detail and search
//
// SPDX-License-Identifier: PolyForm-Noncommercial-1.0.0
// Copyright (C) 2026 Rune Olsen
//
// This file is part of Confab.
//
// Confab is licensed under the PolyForm Noncommercial License 1.0.0.
// You may use, study, modify, and share it for any noncommercial
// purpose. Commercial use — including selling Confab or any part of
// it, standalone or bundled into another product or service —
// requires a separate commercial license from the copyright holder.
//
// See the LICENSE file or
// <https://polyformproject.org/licenses/noncommercial/1.0.0> for
// the full license text. For commercial licensing, contact Rune
// Olsen via <https://confab.no>.


import SwiftUI

// MARK: - Data Model

struct CommandDetail: Identifiable {
    let id = UUID()
    let command: String
    let brief: String
    let detail: String
    let examples: [String]
    var shortcut: String? = nil
}

struct CommandCategory: Identifiable {
    let id = UUID()
    let name: LocalizedStringKey
    let icon: String
    let commands: [CommandDetail]
}

// MARK: - Help Data

private let helpCategories: [CommandCategory] = [
    CommandCategory(name: "Chat", icon: "bubble.left.and.bubble.right", commands: [
        CommandDetail(
            command: "/history",
            brief: "View command history",
            detail: "Opens a searchable modal showing all your previous messages with timestamps in European format (dd.MM.yyyy HH:mm:ss). Search by text content or date to find specific messages. Click any entry to reuse it.",
            examples: ["/history"],
            shortcut: "⇧⌘H"
        ),
        CommandDetail(
            command: "/clear",
            brief: "Clear chat history",
            detail: "Removes all messages from the current session and resets the conversation. This does not delete saved conversations.",
            examples: ["/clear"],
            shortcut: "⌘K"
        ),
        CommandDetail(
            command: "/retry",
            brief: "Retry last message",
            detail: "Resends your last message to the AI. Useful when you get an unsatisfactory response or encounter an error.",
            examples: ["/retry"]
        ),
        CommandDetail(
            command: "/memory on|off",
            brief: "Toggle conversation memory",
            detail: "When enabled, the AI remembers all previous messages in the session. When disabled, each message is treated independently — only your latest message is sent.",
            examples: ["/memory on", "/memory off"]
        ),
        CommandDetail(
            command: "/online on|off",
            brief: "Toggle web search",
            detail: "Enables or disables online mode. When on, the AI can search the web to find current information before responding.",
            examples: ["/online on", "/online off"]
        ),
    ]),
    CommandCategory(name: "Model & Provider", icon: "cpu", commands: [
        CommandDetail(
            command: "/model",
            brief: "Select AI model",
            detail: "Opens the model selector to browse and choose from available models. The list depends on your active provider and API key.",
            examples: ["/model"],
            shortcut: "⌘M"
        ),
        CommandDetail(
            command: "/provider [name]",
            brief: "Switch AI provider",
            detail: "Without arguments, shows the current provider. With a provider name, switches to that provider. Available providers: openrouter, anthropic, openai, ollama.",
            examples: ["/provider", "/provider anthropic", "/provider openai"]
        ),
        CommandDetail(
            command: "/info [model]",
            brief: "Show model information",
            detail: "Displays details about the currently selected model, or a specific model if provided. Shows context length, pricing, and capabilities.",
            examples: ["/info", "/info anthropic/claude-sonnet-4"]
        ),
        CommandDetail(
            command: "/credits",
            brief: "Check account credits",
            detail: "Shows your current balance and usage for the active provider (where supported, e.g. OpenRouter).",
            examples: ["/credits"]
        ),
    ]),
    CommandCategory(name: "Conversations", icon: "tray.full", commands: [
        CommandDetail(
            command: "/save <name>",
            brief: "Save current conversation",
            detail: "Saves all messages in the current session under the given name. You can load it later to continue the conversation.",
            examples: ["/save my-project-chat", "/save debug session"],
            shortcut: "⌘S"
        ),
        CommandDetail(
            command: "/load",
            brief: "Load saved conversation",
            detail: "Opens the conversation list to browse and load a previously saved conversation. Replaces the current chat.",
            examples: ["/load"],
            shortcut: "⌘L"
        ),
        CommandDetail(
            command: "/list",
            brief: "List saved conversations",
            detail: "Opens the conversation list showing all saved conversations with their dates and message counts.",
            examples: ["/list"],
            shortcut: "⌘L"
        ),
        CommandDetail(
            command: "/delete <name>",
            brief: "Delete a saved conversation",
            detail: "Permanently deletes a saved conversation by name. This cannot be undone.",
            examples: ["/delete old-chat", "/delete test"]
        ),
        CommandDetail(
            command: "/export md|html|pdf|json",
            brief: "Export conversation",
            detail: "Exports the current conversation to a file. Supports Markdown (.md), HTML (.html), PDF (.pdf), and JSON (.json) formats. Optionally provide a custom filename.",
            examples: ["/export md", "/export html", "/export pdf", "/export json", "/export md my-chat.md"]
        ),
    ]),
    CommandCategory(name: "MCP (File Access)", icon: "folder.badge.gearshape", commands: [
        CommandDetail(
            command: "/mcp on|off",
            brief: "Toggle file access",
            detail: "Enables or disables MCP (Model Context Protocol), which gives the AI access to read (and optionally write) files in your allowed folders.",
            examples: ["/mcp on", "/mcp off"]
        ),
        CommandDetail(
            command: "/mcp add <path>",
            brief: "Add folder for access",
            detail: "Grants the AI access to a folder on your filesystem. The AI can then read, list, and search files within it. Use absolute paths or ~.",
            examples: ["/mcp add ~/Projects/myapp", "/mcp add /Users/me/Documents"]
        ),
        CommandDetail(
            command: "/mcp remove <index|path>",
            brief: "Remove an allowed folder",
            detail: "Revokes AI access to a folder. Specify by index number (from /mcp list) or by path.",
            examples: ["/mcp remove 0", "/mcp remove ~/Projects/myapp"]
        ),
        CommandDetail(
            command: "/mcp list",
            brief: "List allowed folders",
            detail: "Shows all folders the AI currently has access to, with their index numbers.",
            examples: ["/mcp list"]
        ),
        CommandDetail(
            command: "/mcp status",
            brief: "Show MCP status",
            detail: "Displays whether MCP is enabled, the number of registered folders, active permissions (read/write/delete/move), and gitignore setting.",
            examples: ["/mcp status"]
        ),
        CommandDetail(
            command: "/mcp write on|off",
            brief: "Toggle write permissions",
            detail: "Quickly enables or disables all write permissions (write, edit, delete, create directories, move, copy). Fine-grained control is available in Settings > MCP.",
            examples: ["/mcp write on", "/mcp write off"]
        ),
    ]),
    CommandCategory(name: "Conversation Notes", icon: "note.text", commands: [
        CommandDetail(
            command: "/notes on",
            brief: "Enable notes for this conversation",
            detail: "Turns on a persistent notes.md file for this specific conversation. Once on, the AI reads it automatically on every turn and can update it on its own — no approval needed per write. This is the only consent step; turning it on is always a deliberate, explicit action.",
            examples: ["/notes on"]
        ),
        CommandDetail(
            command: "/notes off",
            brief: "Disable notes for this conversation",
            detail: "Turns off automatic reading and writing of this conversation's notes. The file itself isn't deleted — turning notes back on later picks up where it left off.",
            examples: ["/notes off"]
        ),
        CommandDetail(
            command: "/notes show",
            brief: "Show this conversation's notes",
            detail: "Displays the current contents of this conversation's notes file in the chat, without leaving the app. Notes files also live in Settings > Advanced, where you can open the folder directly in Finder.",
            examples: ["/notes show"]
        ),
    ]),
    CommandCategory(name: "Integrations", icon: "server.rack", commands: [
        CommandDetail(
            command: "/jarvis",
            brief: "Open Jarvis agent manager",
            detail: "Opens the Jarvis panel where you can list, create, run, and monitor agents on your Jarvis (oAI-Web) server, and view usage and cost statistics. Configure the server URL and API key in Settings → Jarvis.",
            examples: ["/jarvis"]
        ),
    ]),
    CommandCategory(name: "Settings & Stats", icon: "gearshape", commands: [
        CommandDetail(
            command: "/config",
            brief: "Open settings",
            detail: "Opens the settings panel where you can configure providers, API keys, MCP permissions, appearance, and more. Also available via /settings.",
            examples: ["/config", "/settings"],
            shortcut: "⌘,"
        ),
        CommandDetail(
            command: "/stats",
            brief: "Show session statistics",
            detail: "Displays statistics for the current session: message count, total tokens used, estimated cost, and session duration.",
            examples: ["/stats"],
            shortcut: "⌘⇧S"
        ),
    ]),
]

private let keyboardShortcuts: [(key: String, description: String)] = [
    ("Return", "Send message"),
    ("Shift + Return", "New line"),
    ("\u{2318}M", "Model Selector"),
    ("\u{2318}K", "Clear Chat"),
    ("\u{2318}H", "Command History"),
    ("\u{2318}L", "Conversations"),
    ("\u{21E7}\u{2318}S", "Statistics"),
    ("\u{2318},", "Settings"),
]

// MARK: - HelpView

struct HelpView: View {
    @Environment(\.dismiss) var dismiss
    @State private var searchText = ""
    @State private var expandedCommandID: UUID?
    private let settings = SettingsService.shared

    private var allCategories: [CommandCategory] {
        var cats = helpCategories
        let shortcuts = settings.userShortcuts
        if !shortcuts.isEmpty {
            let shortcutCommands = shortcuts.map { s in
                CommandDetail(
                    command: s.command + (s.needsInput ? " <text>" : ""),
                    brief: s.description,
                    detail: "Template: \(s.template)",
                    examples: s.needsInput ? ["\(s.command) your text here"] : [s.command]
                )
            }
            cats.append(CommandCategory(name: "Your Shortcuts", icon: "bolt.fill", commands: shortcutCommands))
        }
        let activeSkills = settings.agentSkills.filter { $0.isActive }
        if !activeSkills.isEmpty {
            let skillCommands = activeSkills.map { skill in
                CommandDetail(
                    command: skill.name,
                    brief: skill.skillDescription,
                    detail: "Active skill — injected into system prompt automatically.\n\nContent:\n\(skill.content)",
                    examples: []
                )
            }
            cats.append(CommandCategory(name: "Active Skills", icon: "brain", commands: skillCommands))
        }
        return cats
    }

    private var filteredCategories: [CommandCategory] {
        if searchText.isEmpty { return allCategories }
        let q = searchText.lowercased()
        return allCategories.compactMap { cat in
            let matched = cat.commands.filter {
                $0.command.lowercased().contains(q) ||
                $0.brief.lowercased().contains(q) ||
                $0.detail.lowercased().contains(q) ||
                $0.examples.contains { $0.lowercased().contains(q) }
            }
            return matched.isEmpty ? nil : CommandCategory(name: cat.name, icon: cat.icon, commands: matched)
        }
    }

    private var matchingShortcuts: [(key: String, description: String)] {
        if searchText.isEmpty { return keyboardShortcuts }
        let q = searchText.lowercased()
        return keyboardShortcuts.filter {
            $0.key.lowercased().contains(q) || $0.description.lowercased().contains(q)
        }
    }

    var body: some View {
        VStack(spacing: 0) {
            // Header
            HStack {
                Text("Help")
                    .font(.system(size: 18, weight: .bold))
                Spacer()
                Button { dismiss() } label: {
                    Image(systemName: "xmark.circle.fill")
                        .font(.title2)
                        .foregroundStyle(.secondary)
                }
                .buttonStyle(.plain)
                .keyboardShortcut(.escape, modifiers: [])
            }
            .padding(.horizontal, 24)
            .padding(.top, 20)
            .padding(.bottom, 12)

            // Search bar
            HStack(spacing: 8) {
                Image(systemName: "magnifyingglass")
                    .foregroundStyle(.secondary)
                TextField("Search commands, shortcuts, features...", text: $searchText)
                    .textFieldStyle(.plain)
                if !searchText.isEmpty {
                    Button {
                        searchText = ""
                    } label: {
                        Image(systemName: "xmark.circle.fill")
                            .foregroundStyle(.tertiary)
                    }
                    .buttonStyle(.plain)
                }
            }
            .padding(10)
            .background(.quaternary.opacity(0.5), in: RoundedRectangle(cornerRadius: 8))
            .padding(.horizontal, 24)
            .padding(.bottom, 12)

            Divider()

            // Content
            ScrollView {
                VStack(alignment: .leading, spacing: 20) {
                    // Quick tip (only when not searching)
                    if searchText.isEmpty {
                        HStack(spacing: 10) {
                            Image(systemName: "lightbulb.fill")
                                .foregroundStyle(.yellow)
                                .font(.title3)
                            VStack(alignment: .leading, spacing: 2) {
                                Text("Type / in the input to see command suggestions")
                                    .font(.callout)
                                Text("Use @filename to attach files to your message")
                                    .font(.callout)
                                    .foregroundStyle(.secondary)
                            }
                        }
                        .padding(12)
                        .frame(maxWidth: .infinity, alignment: .leading)
                        .background(.blue.opacity(0.08), in: RoundedRectangle(cornerRadius: 10))
                    }

                    // Command categories
                    ForEach(filteredCategories) { category in
                        CategorySection(
                            category: category,
                            expandedCommandID: $expandedCommandID
                        )
                    }

                    // Keyboard shortcuts
                    #if os(macOS)
                    if !matchingShortcuts.isEmpty {
                        VStack(alignment: .leading, spacing: 8) {
                            Label("Keyboard Shortcuts", systemImage: "keyboard")
                                .font(.system(size: 13, weight: .semibold))
                                .foregroundStyle(.secondary)

                            VStack(spacing: 0) {
                                ForEach(Array(matchingShortcuts.enumerated()), id: \.offset) { idx, shortcut in
                                    HStack {
                                        Text(shortcut.key)
                                            .font(.system(size: 12, weight: .medium, design: .monospaced))
                                            .padding(.horizontal, 8)
                                            .padding(.vertical, 4)
                                            .background(.quaternary, in: RoundedRectangle(cornerRadius: 5))
                                        Spacer()
                                        Text(LocalizedStringKey(shortcut.description))
                                            .font(.callout)
                                            .foregroundStyle(.secondary)
                                    }
                                    .padding(.horizontal, 12)
                                    .padding(.vertical, 6)

                                    if idx < matchingShortcuts.count - 1 {
                                        Divider().padding(.leading, 12)
                                    }
                                }
                            }
                            .background(.background, in: RoundedRectangle(cornerRadius: 10))
                            .overlay(RoundedRectangle(cornerRadius: 10).stroke(.quaternary))
                        }
                    }
                    #endif

                    // No results
                    if filteredCategories.isEmpty && matchingShortcuts.isEmpty {
                        VStack(spacing: 8) {
                            Image(systemName: "magnifyingglass")
                                .font(.largeTitle)
                                .foregroundStyle(.tertiary)
                            Text("No results for \"\(searchText)\"")
                                .font(.callout)
                                .foregroundStyle(.secondary)
                        }
                        .frame(maxWidth: .infinity)
                        .padding(.vertical, 40)
                    }
                }
                .padding(.horizontal, 24)
                .padding(.vertical, 16)
            }

            Divider()

            // Bottom bar
            HStack {
                Spacer()
                Button("Done") { dismiss() }
                    .keyboardShortcut(.return, modifiers: [])
                    .buttonStyle(.borderedProminent)
                    .controlSize(.regular)
                Spacer()
            }
            .padding(.horizontal, 24)
            .padding(.vertical, 12)
        }
        .frame(minWidth: 520, idealWidth: 600, minHeight: 480, idealHeight: 700)
    }
}

// MARK: - Category Section

private struct CategorySection: View {
    let category: CommandCategory
    @Binding var expandedCommandID: UUID?

    var body: some View {
        VStack(alignment: .leading, spacing: 8) {
            Label(category.name, systemImage: category.icon)
                .font(.system(size: 13, weight: .semibold))
                .foregroundStyle(.secondary)

            VStack(spacing: 0) {
                ForEach(Array(category.commands.enumerated()), id: \.element.id) { idx, cmd in
                    CommandRow(
                        command: cmd,
                        isExpanded: expandedCommandID == cmd.id,
                        onTap: {
                            withAnimation(.easeInOut(duration: 0.2)) {
                                expandedCommandID = expandedCommandID == cmd.id ? nil : cmd.id
                            }
                        }
                    )

                    if idx < category.commands.count - 1 {
                        Divider().padding(.leading, 12)
                    }
                }
            }
            .background(.background, in: RoundedRectangle(cornerRadius: 10))
            .overlay(RoundedRectangle(cornerRadius: 10).stroke(.quaternary))
        }
    }
}

// MARK: - Command Row

private struct CommandRow: View {
    let command: CommandDetail
    let isExpanded: Bool
    let onTap: () -> Void

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            // Header (always visible)
            Button(action: onTap) {
                HStack(spacing: 10) {
                    Text(command.command)
                        .font(.system(size: 13, weight: .medium, design: .monospaced))
                        .foregroundStyle(.primary)

                    Text(LocalizedStringKey(command.brief))
                        .font(.callout)
                        .foregroundStyle(.secondary)
                        .lineLimit(1)

                    Spacer()

                    if let shortcut = command.shortcut {
                        Text(shortcut)
                            .font(.system(size: 11, weight: .medium))
                            .foregroundStyle(.secondary)
                            .padding(.horizontal, 6)
                            .padding(.vertical, 2)
                            .background(.quaternary, in: RoundedRectangle(cornerRadius: 5))
                    }

                    Image(systemName: "chevron.right")
                        .font(.caption)
                        .foregroundStyle(.tertiary)
                        .rotationEffect(.degrees(isExpanded ? 90 : 0))
                }
                .contentShape(Rectangle())
                .padding(.horizontal, 12)
                .padding(.vertical, 10)
            }
            .buttonStyle(.plain)

            // Expanded detail
            if isExpanded {
                VStack(alignment: .leading, spacing: 10) {
                    Text(LocalizedStringKey(command.detail))
                        .font(.callout)
                        .foregroundStyle(.primary)
                        .fixedSize(horizontal: false, vertical: true)

                    if !command.examples.isEmpty {
                        VStack(alignment: .leading, spacing: 6) {
                            Text(command.examples.count == 1 ? "Example" as LocalizedStringKey : "Examples")
                                .font(.caption)
                                .foregroundStyle(.secondary)
                                .fontWeight(.medium)

                            ForEach(command.examples, id: \.self) { example in
                                Text(example)
                                    .font(.system(size: 12, design: .monospaced))
                                    .padding(.horizontal, 10)
                                    .padding(.vertical, 6)
                                    .frame(maxWidth: .infinity, alignment: .leading)
                                    .background(.blue.opacity(0.06), in: RoundedRectangle(cornerRadius: 6))
                            }
                        }
                    }
                }
                .padding(.horizontal, 12)
                .padding(.bottom, 12)
                .transition(.opacity.combined(with: .move(edge: .top)))
            }
        }
    }
}

#Preview {
    HelpView()
}
