//! Claude vendor definition
//!
//! This module contains all Claude-specific knowledge including CLI detection,
//! mode/model mappings, and connector templates.

use super::{MappingResult, ModeMapping, ModelMapping, VendorInfo};
use crate::connectors::acp::config::ConnectorAgentType;

/// Claude mode identifiers
pub mod modes {
    pub const DEFAULT: &str = "default";
    pub const PLAN: &str = "plan";
    pub const ACCEPT_EDITS: &str = "acceptEdits";
    pub const BYPASS_PERMISSIONS: &str = "bypassPermissions";
}

/// Claude model identifiers
pub mod models {
    pub const DEFAULT: &str = "default";
    pub const HAIKU: &str = "haiku";
    pub const SONNET: &str = "sonnet";
    pub const OPUS: &str = "opus";
}

/// Gateway mode identifiers (for reference)
mod gateway_modes {
    pub const PLAN: &str = "plan";
    pub const READONLY: &str = "readonly";
    pub const ASK: &str = "ask";
    pub const WRITE: &str = "write";
    pub const YOLO: &str = "yolo";
}

/// Gateway model identifiers (for reference)
mod gateway_models {
    pub const SIMPLE: &str = "simple";
    pub const DAILYDRIVER: &str = "dailydriver";
    pub const HIGH: &str = "high";
}

/// Static mode mappings for Claude
static MODE_MAPPINGS: &[ModeMapping] = &[
    ModeMapping {
        gateway: gateway_modes::ASK,
        vendor: modes::DEFAULT,
    },
    ModeMapping {
        gateway: gateway_modes::PLAN,
        vendor: modes::PLAN,
    },
    ModeMapping {
        gateway: gateway_modes::WRITE,
        vendor: modes::ACCEPT_EDITS,
    },
    ModeMapping {
        gateway: gateway_modes::YOLO,
        vendor: modes::BYPASS_PERMISSIONS,
    },
];

/// Static model mappings for Claude
static MODEL_MAPPINGS: &[ModelMapping] = &[
    ModelMapping {
        gateway: gateway_models::SIMPLE,
        vendor: models::HAIKU,
    },
    ModelMapping {
        gateway: gateway_models::DAILYDRIVER,
        vendor: models::SONNET,
    },
    ModelMapping {
        gateway: gateway_models::HIGH,
        vendor: models::OPUS,
    },
];

/// Claude vendor implementation
pub struct ClaudeVendor;

impl VendorInfo for ClaudeVendor {
    fn id(&self) -> &'static str {
        "claude"
    }

    fn display_name(&self) -> &'static str {
        "Claude"
    }

    fn aliases(&self) -> &'static [&'static str] {
        &["anthropic"]
    }

    fn agent_type(&self) -> ConnectorAgentType {
        ConnectorAgentType::Claude
    }

    fn cli_command(&self) -> &'static str {
        "claude"
    }

    fn cli_args(&self) -> &'static [&'static str] {
        &["--acp"]
    }

    fn mode_mappings(&self) -> &'static [ModeMapping] {
        MODE_MAPPINGS
    }

    fn model_mappings(&self) -> &'static [ModelMapping] {
        MODEL_MAPPINGS
    }

    fn map_mode(&self, gateway_mode: &str) -> MappingResult {
        match gateway_mode {
            gateway_modes::ASK => MappingResult::exact(modes::DEFAULT),
            gateway_modes::PLAN => MappingResult::exact(modes::PLAN),
            gateway_modes::READONLY => MappingResult::approximate(
                modes::PLAN,
                "Gateway 'readonly' mode mapped to Claude 'plan' mode",
            ),
            gateway_modes::WRITE => MappingResult::exact(modes::ACCEPT_EDITS),
            gateway_modes::YOLO => MappingResult::exact(modes::BYPASS_PERMISSIONS),
            _ => MappingResult::approximate(
                modes::DEFAULT,
                format!("Unknown gateway mode '{}' mapped to Claude 'default' mode", gateway_mode),
            ),
        }
    }

    fn map_model(&self, gateway_model: &str) -> MappingResult {
        match gateway_model {
            gateway_models::SIMPLE => MappingResult::exact(models::HAIKU),
            gateway_models::DAILYDRIVER => MappingResult::exact(models::SONNET),
            gateway_models::HIGH => MappingResult::exact(models::OPUS),
            _ => MappingResult::approximate(
                models::SONNET,
                format!(
                    "Unknown gateway model '{}' mapped to Claude 'sonnet' model",
                    gateway_model
                ),
            ),
        }
    }

    fn reverse_map_mode(&self, vendor_mode: &str) -> MappingResult {
        match vendor_mode {
            modes::DEFAULT => MappingResult::exact(gateway_modes::ASK),
            modes::PLAN => MappingResult::exact(gateway_modes::PLAN),
            modes::ACCEPT_EDITS => MappingResult::exact(gateway_modes::WRITE),
            modes::BYPASS_PERMISSIONS => MappingResult::exact(gateway_modes::YOLO),
            _ => MappingResult::approximate(
                gateway_modes::ASK,
                format!("Unknown Claude mode '{}' mapped to Gateway 'ask' mode", vendor_mode),
            ),
        }
    }

    fn reverse_map_model(&self, vendor_model: &str) -> MappingResult {
        match vendor_model {
            models::HAIKU => MappingResult::exact(gateway_models::SIMPLE),
            models::SONNET => MappingResult::exact(gateway_models::DAILYDRIVER),
            models::OPUS => MappingResult::exact(gateway_models::HIGH),
            models::DEFAULT => MappingResult::exact(gateway_models::DAILYDRIVER),
            _ => MappingResult::approximate(
                gateway_models::DAILYDRIVER,
                format!(
                    "Unknown Claude model '{}' mapped to Gateway 'dailydriver' model",
                    vendor_model
                ),
            ),
        }
    }

    fn acp_template(&self) -> serde_json::Value {
        serde_json::json!({
            "transport": {
                "type": "stdio",
                "command": "claude",
                "args": ["--acp"]
            },
            "protocol_version": 1,
            "cwd": ".",
            "retry": {
                "max_retries": 5,
                "retry_delays_ms": [1000, 3000, 5000, 5000, 5000]
            }
        })
    }

    fn default_features(&self) -> &'static [&'static str] {
        // Claude Code has limited ACP support:
        // - NOT session_resume: generates ephemeral ACP session IDs
        // - NOT cancellation: session/cancel not implemented
        &[]
    }

    fn icon_path(&self) -> &'static str {
        "claude"
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_claude_vendor_id() {
        let vendor = ClaudeVendor;
        assert_eq!(vendor.id(), "claude");
        assert_eq!(vendor.display_name(), "Claude");
        assert_eq!(vendor.aliases(), &["anthropic"]);
    }

    #[test]
    fn test_claude_mode_mappings() {
        let vendor = ClaudeVendor;

        // Forward mappings
        assert_eq!(vendor.map_mode("ask").mapped_id, "default");
        assert_eq!(vendor.map_mode("plan").mapped_id, "plan");
        assert_eq!(vendor.map_mode("write").mapped_id, "acceptEdits");
        assert_eq!(vendor.map_mode("yolo").mapped_id, "bypassPermissions");

        // Reverse mappings
        assert_eq!(vendor.reverse_map_mode("default").mapped_id, "ask");
        assert_eq!(vendor.reverse_map_mode("plan").mapped_id, "plan");
        assert_eq!(vendor.reverse_map_mode("acceptEdits").mapped_id, "write");
        assert_eq!(vendor.reverse_map_mode("bypassPermissions").mapped_id, "yolo");
    }

    #[test]
    fn test_claude_model_mappings() {
        let vendor = ClaudeVendor;

        // Forward mappings
        assert_eq!(vendor.map_model("simple").mapped_id, "haiku");
        assert_eq!(vendor.map_model("dailydriver").mapped_id, "sonnet");
        assert_eq!(vendor.map_model("high").mapped_id, "opus");

        // Reverse mappings
        assert_eq!(vendor.reverse_map_model("haiku").mapped_id, "simple");
        assert_eq!(vendor.reverse_map_model("sonnet").mapped_id, "dailydriver");
        assert_eq!(vendor.reverse_map_model("opus").mapped_id, "high");
    }

    #[test]
    fn test_claude_unknown_mode() {
        let vendor = ClaudeVendor;
        let result = vendor.map_mode("unknown");
        assert_eq!(result.mapped_id, "default");
        assert!(result.warning.is_some());
    }

    #[test]
    fn test_claude_cli() {
        let vendor = ClaudeVendor;
        assert_eq!(vendor.cli_command(), "claude");
        assert_eq!(vendor.cli_args(), &["--acp"]);
    }
}
