//! Vendor registry for agent-specific knowledge
//!
//! This module consolidates vendor-specific configuration and behavior into a single location.
//! When adding support for a new vendor (Claude, Codex, Gemini, etc.), create a new module
//! in this directory implementing the `VendorInfo` trait.
//!
//! # Adding a New Vendor
//!
//! 1. Create a new file in `vendors/` (e.g., `gemini.rs`)
//! 2. Implement the `VendorInfo` trait for your vendor
//! 3. Register your vendor in the `VENDOR_REGISTRY` in this file
//!
//! # Example
//!
//! ```rust,ignore
//! use dirigent_core::vendors::{VENDOR_REGISTRY, VendorInfo};
//!
//! // Look up vendor by ID
//! if let Some(vendor) = VENDOR_REGISTRY.get("claude") {
//!     println!("CLI command: {}", vendor.cli_command());
//!     println!("Display name: {}", vendor.display_name());
//! }
//!
//! // Detect which vendors are available on the system
//! let available = VENDOR_REGISTRY.detect_available();
//! for vendor in available {
//!     println!("{} is installed", vendor.display_name());
//! }
//! ```

pub mod claude;
mod codex;
mod custom;
mod gemini;
mod registry;

pub use claude::ClaudeVendor;
pub use codex::CodexVendor;
pub use custom::CustomVendor;
pub use gemini::GeminiVendor;
pub use registry::{VendorRegistry, VENDOR_REGISTRY};

use crate::connectors::acp::config::ConnectorAgentType;

/// Mode mapping entry
#[derive(Debug, Clone)]
pub struct ModeMapping {
    /// Gateway mode identifier
    pub gateway: &'static str,
    /// Vendor-specific mode identifier
    pub vendor: &'static str,
}

/// Model mapping entry
#[derive(Debug, Clone)]
pub struct ModelMapping {
    /// Gateway model identifier
    pub gateway: &'static str,
    /// Vendor-specific model identifier
    pub vendor: &'static str,
}

/// Result of a mode/model mapping operation
#[derive(Debug, Clone, PartialEq)]
pub struct MappingResult {
    /// The mapped identifier
    pub mapped_id: String,
    /// Warning message if mapping was approximate
    pub warning: Option<String>,
}

impl MappingResult {
    /// Create an exact mapping result
    pub fn exact(id: impl Into<String>) -> Self {
        Self {
            mapped_id: id.into(),
            warning: None,
        }
    }

    /// Create an approximate mapping with a warning
    pub fn approximate(id: impl Into<String>, warning: impl Into<String>) -> Self {
        Self {
            mapped_id: id.into(),
            warning: Some(warning.into()),
        }
    }
}

/// Trait defining vendor-specific knowledge
///
/// Implement this trait for each vendor (Claude, Codex, Gemini, etc.) to consolidate
/// all vendor-specific configuration in one place.
pub trait VendorInfo: Send + Sync {
    /// Unique vendor identifier (lowercase, e.g., "claude", "codex")
    fn id(&self) -> &'static str;

    /// Human-readable display name (e.g., "Claude", "Codex")
    fn display_name(&self) -> &'static str;

    /// Alternative names that map to this vendor (e.g., ["anthropic"] for Claude)
    fn aliases(&self) -> &'static [&'static str] {
        &[]
    }

    /// The corresponding ConnectorAgentType enum value
    fn agent_type(&self) -> ConnectorAgentType;

    // =========================================================================
    // CLI Detection
    // =========================================================================

    /// CLI command name for this vendor (e.g., "claude" for Claude)
    fn cli_command(&self) -> &'static str;

    /// Default CLI arguments (e.g., ["--acp"] for Claude)
    fn cli_args(&self) -> &'static [&'static str] {
        &[]
    }

    /// CLI command name on Windows (defaults to cli_command)
    fn cli_command_windows(&self) -> &'static str {
        self.cli_command()
    }

    // =========================================================================
    // Mode/Model Mappings
    // =========================================================================

    /// Mode mappings from Gateway identifiers to vendor-specific identifiers
    fn mode_mappings(&self) -> &'static [ModeMapping] {
        &[]
    }

    /// Model mappings from Gateway identifiers to vendor-specific identifiers
    fn model_mappings(&self) -> &'static [ModelMapping] {
        &[]
    }

    /// Map a Gateway mode to vendor-specific mode
    fn map_mode(&self, gateway_mode: &str) -> MappingResult {
        for mapping in self.mode_mappings() {
            if mapping.gateway == gateway_mode {
                return MappingResult::exact(mapping.vendor);
            }
        }
        // Default: pass through with warning
        MappingResult::approximate(
            gateway_mode,
            format!(
                "Unknown mode '{}' for {}",
                gateway_mode,
                self.display_name()
            ),
        )
    }

    /// Map a Gateway model to vendor-specific model
    fn map_model(&self, gateway_model: &str) -> MappingResult {
        for mapping in self.model_mappings() {
            if mapping.gateway == gateway_model {
                return MappingResult::exact(mapping.vendor);
            }
        }
        // Default: pass through with warning
        MappingResult::approximate(
            gateway_model,
            format!(
                "Unknown model '{}' for {}",
                gateway_model,
                self.display_name()
            ),
        )
    }

    /// Reverse map a vendor-specific mode to Gateway mode
    fn reverse_map_mode(&self, vendor_mode: &str) -> MappingResult {
        for mapping in self.mode_mappings() {
            if mapping.vendor == vendor_mode {
                return MappingResult::exact(mapping.gateway);
            }
        }
        // Default: pass through with warning
        MappingResult::approximate(
            vendor_mode,
            format!("Unknown {} mode '{}'", self.display_name(), vendor_mode),
        )
    }

    /// Reverse map a vendor-specific model to Gateway model
    fn reverse_map_model(&self, vendor_model: &str) -> MappingResult {
        for mapping in self.model_mappings() {
            if mapping.vendor == vendor_model {
                return MappingResult::exact(mapping.gateway);
            }
        }
        // Default: pass through with warning
        MappingResult::approximate(
            vendor_model,
            format!("Unknown {} model '{}'", self.display_name(), vendor_model),
        )
    }

    // =========================================================================
    // Templates & Defaults
    // =========================================================================

    /// Default ACP connector template for this vendor
    fn acp_template(&self) -> serde_json::Value {
        serde_json::json!({})
    }

    /// Default supported features for this vendor
    fn default_features(&self) -> &'static [&'static str] {
        &[]
    }

    /// Default icon path for this vendor
    fn icon_path(&self) -> &'static str {
        "acp"
    }
}
