/// Application state management via Dioxus signals.
///
/// Analogous to Svelte 5 runes ($state, $derived) — Dioxus signals provide
/// automatic dependency tracking and targeted re-renders.

use serde::{Deserialize, Serialize};
use uuid::Uuid;

/// Agent activity status — mirrors the Svelte health store's ActivityState.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AgentStatus {
    Idle,
    Running,
    Done,
    Stalled,
    Error,
}

impl AgentStatus {
    pub fn css_class(&self) -> &'static str {
        match self {
            AgentStatus::Idle => "idle",
            AgentStatus::Running => "running",
            AgentStatus::Done => "done",
            AgentStatus::Stalled => "stalled",
            AgentStatus::Error => "error",
        }
    }

    pub fn label(&self) -> &'static str {
        match self {
            AgentStatus::Idle => "Idle",
            AgentStatus::Running => "Running",
            AgentStatus::Done => "Done",
            AgentStatus::Stalled => "Stalled",
            AgentStatus::Error => "Error",
        }
    }
}

/// A single message in an agent conversation.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct AgentMessage {
    pub id: String,
    pub role: MessageRole,
    pub content: String,
    /// For tool calls: tool name
    pub tool_name: Option<String>,
    /// For tool results: output text
    pub tool_output: Option<String>,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MessageRole {
    User,
    Assistant,
    Tool,
}

impl MessageRole {
    pub fn css_class(&self) -> &'static str {
        match self {
            MessageRole::User => "user",
            MessageRole::Assistant => "assistant",
            MessageRole::Tool => "tool",
        }
    }

    pub fn label(&self) -> &'static str {
        match self {
            MessageRole::User => "You",
            MessageRole::Assistant => "Claude",
            MessageRole::Tool => "Tool",
        }
    }
}

/// Which tab is active in a ProjectBox.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ProjectTab {
    Model,
    Docs,
    Files,
}

impl ProjectTab {
    pub fn label(&self) -> &'static str {
        match self {
            ProjectTab::Model => "Model",
            ProjectTab::Docs => "Docs",
            ProjectTab::Files => "Files",
        }
    }

    pub fn all() -> &'static [ProjectTab] {
        &[ProjectTab::Model, ProjectTab::Docs, ProjectTab::Files]
    }
}

/// A project configuration — corresponds to GroupsFile ProjectConfig in the Svelte app.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub struct ProjectConfig {
    pub id: String,
    pub name: String,
    pub cwd: String,
    pub provider: String,
    pub accent: String,
}

impl ProjectConfig {
    pub fn new(name: &str, cwd: &str, provider: &str, accent: &str) -> Self {
        Self {
            id: Uuid::new_v4().to_string(),
            name: name.to_string(),
            cwd: cwd.to_string(),
            provider: provider.to_string(),
            accent: accent.to_string(),
        }
    }
}

/// Per-project agent session state.
#[derive(Debug, Clone)]
pub struct AgentSession {
    pub session_id: String,
    pub status: AgentStatus,
    pub messages: Vec<AgentMessage>,
    pub cost_usd: f64,
    pub tokens_used: u64,
    pub model: String,
}

impl AgentSession {
    pub fn new() -> Self {
        Self {
            session_id: Uuid::new_v4().to_string(),
            status: AgentStatus::Idle,
            messages: Vec::new(),
            cost_usd: 0.0,
            tokens_used: 0,
            model: "claude-sonnet-4-20250514".to_string(),
        }
    }
}

/// Global app state — sidebar, command palette visibility, etc.
/// (Used when wiring backend; prototype uses individual signals.)
#[derive(Debug, Clone, PartialEq)]
#[allow(dead_code)]
pub struct AppState {
    pub settings_open: bool,
    pub palette_open: bool,
}

impl Default for AppState {
    fn default() -> Self {
        Self {
            settings_open: false,
            palette_open: false,
        }
    }
}

/// Terminal output line for the mock terminal display.
#[derive(Debug, Clone, PartialEq)]
pub struct TerminalLine {
    pub kind: TerminalLineKind,
    pub text: String,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TerminalLineKind {
    Prompt,
    Output,
}

/// Create demo projects for the prototype.
pub fn demo_projects() -> Vec<ProjectConfig> {
    vec![
        ProjectConfig::new(
            "agent-orchestrator",
            "~/code/ai/agent-orchestrator",
            "claude",
            "#89b4fa", // blue
        ),
        ProjectConfig::new(
            "quanta-discord-bot",
            "~/code/bots/quanta-discord-bot",
            "claude",
            "#a6e3a1", // green
        ),
    ]
}

/// Create demo messages for a project agent pane.
pub fn demo_messages() -> Vec<AgentMessage> {
    vec![
        AgentMessage {
            id: "m1".to_string(),
            role: MessageRole::User,
            content: "Add error handling to the WebSocket reconnection logic. It should use \
                      exponential backoff with a 30s cap."
                .to_string(),
            tool_name: None,
            tool_output: None,
        },
        AgentMessage {
            id: "m2".to_string(),
            role: MessageRole::Assistant,
            content: "I'll add exponential backoff to the WebSocket reconnection in \
                      `remote.rs`. Let me first read the current implementation."
                .to_string(),
            tool_name: None,
            tool_output: None,
        },
        AgentMessage {
            id: "m3".to_string(),
            role: MessageRole::Tool,
            content: "Read src-tauri/src/remote.rs".to_string(),
            tool_name: Some("Read".to_string()),
            tool_output: Some(
                "pub struct RemoteManager {\n    connections: HashMap<String, WebSocketConn>,\n    \
                 reconnect_attempts: HashMap<String, u32>,\n}"
                    .to_string(),
            ),
        },
        AgentMessage {
            id: "m4".to_string(),
            role: MessageRole::Assistant,
            content: "I can see the current implementation tracks reconnect attempts but \
                      doesn't implement backoff. I'll add the exponential backoff logic \
                      with a 30-second cap."
                .to_string(),
            tool_name: None,
            tool_output: None,
        },
        AgentMessage {
            id: "m5".to_string(),
            role: MessageRole::Tool,
            content: "Edit src-tauri/src/remote.rs".to_string(),
            tool_name: Some("Edit".to_string()),
            tool_output: Some(
                "Added reconnect_with_backoff() method:\n\
                 - Base delay: 1s\n\
                 - Multiplier: 2x per attempt\n\
                 - Cap: 30s\n\
                 - Max retries: 5"
                    .to_string(),
            ),
        },
        AgentMessage {
            id: "m6".to_string(),
            role: MessageRole::Assistant,
            content: "Done. The WebSocket reconnection now uses exponential backoff \
                      (1s -> 2s -> 4s -> 8s -> 16s -> 30s cap). Added \
                      `reconnect_with_backoff()` method with 5 max retries before \
                      giving up and emitting a `remote-machine-failed` event."
                .to_string(),
            tool_name: None,
            tool_output: None,
        },
    ]
}

/// Demo terminal output lines.
pub fn demo_terminal_lines() -> Vec<TerminalLine> {
    vec![
        TerminalLine {
            kind: TerminalLineKind::Prompt,
            text: "~/code/ai/agent-orchestrator $ ".to_string(),
        },
        TerminalLine {
            kind: TerminalLineKind::Output,
            text: "cargo test --workspace".to_string(),
        },
        TerminalLine {
            kind: TerminalLineKind::Output,
            text: "   Compiling agor-core v0.1.0".to_string(),
        },
        TerminalLine {
            kind: TerminalLineKind::Output,
            text: "   Compiling agor-dioxus v0.1.0".to_string(),
        },
        TerminalLine {
            kind: TerminalLineKind::Output,
            text: "     Running tests/unit.rs".to_string(),
        },
        TerminalLine {
            kind: TerminalLineKind::Output,
            text: "test result: ok. 47 passed; 0 failed".to_string(),
        },
        TerminalLine {
            kind: TerminalLineKind::Prompt,
            text: "~/code/ai/agent-orchestrator $ ".to_string(),
        },
    ]
}

/// Command palette command entries.
#[derive(Debug, Clone)]
pub struct PaletteCommand {
    pub label: String,
    pub shortcut: Option<String>,
    pub icon: String,
}

pub fn palette_commands() -> Vec<PaletteCommand> {
    vec![
        PaletteCommand {
            label: "New Agent Session".to_string(),
            shortcut: Some("Ctrl+N".to_string()),
            icon: "\u{25B6}".to_string(), // play
        },
        PaletteCommand {
            label: "Stop Agent".to_string(),
            shortcut: Some("Ctrl+C".to_string()),
            icon: "\u{25A0}".to_string(), // stop
        },
        PaletteCommand {
            label: "Toggle Settings".to_string(),
            shortcut: Some("Ctrl+,".to_string()),
            icon: "\u{2699}".to_string(), // gear
        },
        PaletteCommand {
            label: "Switch Project Group".to_string(),
            shortcut: Some("Ctrl+G".to_string()),
            icon: "\u{25A3}".to_string(), // box
        },
        PaletteCommand {
            label: "Focus Next Project".to_string(),
            shortcut: Some("Ctrl+]".to_string()),
            icon: "\u{2192}".to_string(), // arrow right
        },
        PaletteCommand {
            label: "Toggle Terminal".to_string(),
            shortcut: Some("Ctrl+`".to_string()),
            icon: "\u{2588}".to_string(), // terminal
        },
        PaletteCommand {
            label: "Search Everything".to_string(),
            shortcut: Some("Ctrl+Shift+F".to_string()),
            icon: "\u{1F50D}".to_string(), // magnifying glass (will render as text)
        },
        PaletteCommand {
            label: "Reload Agent Config".to_string(),
            shortcut: None,
            icon: "\u{21BB}".to_string(), // reload
        },
    ]
}
