//! Plugin system for extending VAPORA lifecycle adapter
//!
//! Allows custom plugins to extend functionality.

use serde::{Deserialize, Serialize};

/// Plugin trait
pub trait LifecyclePlugin: Send + Sync {
    /// Get plugin name
    fn name(&self) -> &str;

    /// Get plugin version
    fn version(&self) -> &str;

    /// Initialize plugin
    fn init(&mut self) -> anyhow::Result<()>;

    /// Handle lifecycle event
    fn on_event(&self, _event: &str, _data: &serde_json::Value) -> anyhow::Result<()> {
        Ok(())
    }

    /// Handle phase transition
    fn on_phase_transition(&self, _project_id: &str, _from: &str, _to: &str) -> anyhow::Result<()> {
        Ok(())
    }
}

/// Plugin metadata
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct PluginMetadata {
    /// Plugin name
    pub name: String,
    /// Plugin version
    pub version: String,
    /// Plugin description
    pub description: String,
    /// Author name
    pub author: String,
    /// Plugin entry point
    pub entry_point: String,
}

/// Plugin registry
#[derive(Debug, Default)]
pub struct PluginRegistry {
    plugins: Vec<PluginMetadata>,
}

impl PluginRegistry {
    /// Create new registry
    pub fn new() -> Self {
        Self::default()
    }

    /// Register plugin
    pub fn register(&mut self, metadata: PluginMetadata) {
        self.plugins.push(metadata);
    }

    /// List registered plugins
    pub fn list(&self) -> &[PluginMetadata] {
        &self.plugins
    }

    /// Get plugin by name
    pub fn get(&self, name: &str) -> Option<&PluginMetadata> {
        self.plugins.iter().find(|p| p.name == name)
    }

    /// Count plugins
    pub fn count(&self) -> usize {
        self.plugins.len()
    }
}

/// Built-in lifecycle plugin
#[derive(Debug)]
pub struct LifecyclePluginImpl {
    name: String,
    version: String,
}

impl LifecyclePluginImpl {
    /// Create new instance
    pub fn new(name: &str, version: &str) -> Self {
        Self {
            name: name.to_string(),
            version: version.to_string(),
        }
    }
}

impl LifecyclePlugin for LifecyclePluginImpl {
    fn name(&self) -> &str {
        &self.name
    }

    fn version(&self) -> &str {
        &self.version
    }

    fn init(&mut self) -> anyhow::Result<()> {
        tracing::info!("Plugin {} initialized", self.name);
        Ok(())
    }

    fn on_phase_transition(&self, project_id: &str, from: &str, to: &str) -> anyhow::Result<()> {
        tracing::info!(
            "Project {} transitioned from {} to {}",
            project_id,
            from,
            to
        );
        Ok(())
    }
}

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

    #[test]
    fn test_plugin_metadata() {
        let meta = PluginMetadata {
            name: "test-plugin".to_string(),
            version: "1.0.0".to_string(),
            description: "A test plugin".to_string(),
            author: "Test Author".to_string(),
            entry_point: "/path/to/plugin".to_string(),
        };

        assert_eq!(meta.name, "test-plugin");
        assert_eq!(meta.version, "1.0.0");
    }

    #[test]
    fn test_plugin_registry() {
        let mut registry = PluginRegistry::new();
        let meta = PluginMetadata {
            name: "test".to_string(),
            version: "1.0.0".to_string(),
            description: "Test".to_string(),
            author: "Test".to_string(),
            entry_point: "/test".to_string(),
        };

        registry.register(meta);
        assert_eq!(registry.count(), 1);
        assert!(registry.get("test").is_some());
    }

    #[test]
    fn test_registry_list() {
        let mut registry = PluginRegistry::new();
        let meta = PluginMetadata {
            name: "test".to_string(),
            version: "1.0.0".to_string(),
            description: "Test".to_string(),
            author: "Test".to_string(),
            entry_point: "/test".to_string(),
        };

        registry.register(meta);
        let list = registry.list();
        assert_eq!(list.len(), 1);
    }

    #[test]
    fn test_lifecycle_plugin_impl() {
        let plugin = LifecyclePluginImpl::new("test", "1.0.0");
        assert_eq!(plugin.name(), "test");
        assert_eq!(plugin.version(), "1.0.0");
    }

    #[test]
    fn test_lifecycle_plugin_init() {
        let mut plugin = LifecyclePluginImpl::new("test", "1.0.0");
        let result = plugin.init();
        assert!(result.is_ok());
    }

    #[test]
    fn test_lifecycle_plugin_phase_transition() {
        let plugin = LifecyclePluginImpl::new("test", "1.0.0");
        let result = plugin.on_phase_transition("proj1", "planning", "design");
        assert!(result.is_ok());
    }
}
