//! Dynamic registry of Importer implementations. Populated at boot.

use std::collections::HashMap;
use std::sync::Arc;

use super::trait_def::{Importer, ImporterInfo};

pub struct ImporterRegistry {
    importers: HashMap<&'static str, Arc<dyn Importer>>,
}

impl ImporterRegistry {
    pub fn new() -> Self {
        Self {
            importers: HashMap::new(),
        }
    }

    /// Populate with all built-in importers. Feature flags select which ship.
    pub fn with_defaults() -> Self {
        let mut r = Self::new();
        #[cfg(feature = "importer-claude")]
        r.register(Arc::new(super::sources::claude::ClaudeImporter));
        #[cfg(feature = "importer-chatgpt")]
        r.register(Arc::new(super::sources::chatgpt::ChatGptImporter));
        #[cfg(feature = "importer-codex")]
        r.register(Arc::new(super::sources::codex::CodexImporter));
        r
    }

    pub fn register(&mut self, importer: Arc<dyn Importer>) {
        self.importers.insert(importer.source_name(), importer);
    }

    pub fn get(&self, name: &str) -> Option<Arc<dyn Importer>> {
        self.importers.get(name).cloned()
    }

    pub fn list(&self) -> Vec<ImporterInfo> {
        self.importers
            .values()
            .map(|i| ImporterInfo {
                source_name: i.source_name().to_string(),
                display_name: pretty_name(i.source_name()),
                config_shape: i.config_shape(),
            })
            .collect()
    }
}

fn pretty_name(source: &str) -> String {
    match source {
        "claude" => "Claude Code".into(),
        "chatgpt" => "ChatGPT (OpenAI)".into(),
        "codex" => "OpenAI Codex".into(),
        other => other.to_string(),
    }
}

impl Default for ImporterRegistry {
    fn default() -> Self {
        Self::with_defaults()
    }
}

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

    #[test]
    fn defaults_include_claude_when_feature_enabled() {
        let reg = ImporterRegistry::with_defaults();
        let list = reg.list();
        #[cfg(feature = "importer-claude")]
        {
            assert!(list.iter().any(|i| i.source_name == "claude"));
            assert!(reg.get("claude").is_some());
        }
        #[cfg(not(feature = "importer-claude"))]
        {
            let _ = list;
            assert!(reg.get("claude").is_none());
        }
    }

    #[test]
    fn pretty_name_known_sources() {
        assert_eq!(pretty_name("claude"), "Claude Code");
        assert_eq!(pretty_name("chatgpt"), "ChatGPT (OpenAI)");
        assert_eq!(pretty_name("codex"), "OpenAI Codex");
        assert_eq!(pretty_name("custom"), "custom");
    }
}
