//! Pure component traits for Rustelo framework
//!
//! This crate provides the core abstractions for components without any
//! dependencies or code generation. These traits define the contracts that page
//! and component implementations must fulfill to work with the Rustelo
//! framework.
//!
//! ## Key Principles
//!
//! - **Zero dependencies**: No external crates, no std beyond core
//! - **No code generation**: Pure trait definitions
//! - **No environment variables**: No build-time configuration
//! - **Generic by design**: Uses associated types and generic parameters
//!
//! ## Architecture
//!
//! The component system is built around these main abstractions:
//!
//! 1. **PageProvider**: Provides access to page components
//! 2. **ComponentRenderer**: Renders individual components
//! 3. **LayoutProvider**: Provides layout and theming capabilities
//! 4. **ContentProvider**: Provides access to content and data

#![forbid(unsafe_code)]
#![warn(missing_docs)]
#![warn(clippy::all)]

use core::fmt;
use std::collections::HashMap;

/// Core result type for component operations
pub type ComponentResult<T> = Result<T, ComponentError>;

/// Errors that can occur during component operations
#[derive(Debug, Clone, PartialEq)]
pub enum ComponentError {
    /// Component not found
    NotFound(String),
    /// Component rendering failed
    RenderError(String),
    /// Layout error
    LayoutError(String),
    /// Content loading failed
    ContentError(String),
}

impl fmt::Display for ComponentError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            ComponentError::NotFound(component) => write!(f, "Component not found: {}", component),
            ComponentError::RenderError(msg) => write!(f, "Render error: {}", msg),
            ComponentError::LayoutError(msg) => write!(f, "Layout error: {}", msg),
            ComponentError::ContentError(msg) => write!(f, "Content error: {}", msg),
        }
    }
}

/// Trait for providing page components
///
/// This abstraction allows different implementations to provide their own
/// page components while maintaining a consistent interface for the routing
/// system.
pub trait PageProvider {
    /// The component type this provider works with
    type Component;

    /// The view type produced by components
    type View;

    /// Properties/parameters passed to components
    type Props;

    /// Get a page component by identifier
    ///
    /// # Arguments
    /// * `component_id` - The identifier for the component
    fn get_component(&self, component_id: &str) -> ComponentResult<Self::Component>;

    /// Render a component with properties
    ///
    /// # Arguments
    /// * `component` - The component to render
    /// * `props` - Properties to pass to the component
    /// * `language` - The language code for rendering
    fn render_component(
        &self,
        component: &Self::Component,
        props: Self::Props,
        language: &str,
    ) -> ComponentResult<Self::View>;

    /// Check if a component exists
    ///
    /// # Arguments
    /// * `component_id` - The identifier to check
    fn has_component(&self, component_id: &str) -> bool {
        self.get_component(component_id).is_ok()
    }

    /// List all available component identifiers
    fn list_components(&self) -> Vec<String>;
}

/// Trait for rendering individual components
///
/// This provides a lower-level interface for component rendering,
/// useful for custom rendering pipelines or component composition.
pub trait ComponentRenderer {
    /// The component type this renderer works with
    type Component;

    /// The view type produced by rendering
    type View;

    /// Context passed during rendering
    type Context;

    /// Render a component with context
    ///
    /// # Arguments
    /// * `component` - The component to render
    /// * `context` - Rendering context
    fn render(
        &self,
        component: &Self::Component,
        context: &Self::Context,
    ) -> ComponentResult<Self::View>;

    /// Pre-process a component before rendering
    ///
    /// # Arguments
    /// * `component` - The component to pre-process
    /// * `context` - Rendering context
    fn pre_render(
        &self,
        component: &Self::Component,
        context: &Self::Context,
    ) -> ComponentResult<()> {
        // Default implementation does nothing
        let _ = (component, context);
        Ok(())
    }

    /// Post-process after rendering
    ///
    /// # Arguments
    /// * `view` - The rendered view
    /// * `context` - Rendering context
    fn post_render(&self, view: &mut Self::View, context: &Self::Context) -> ComponentResult<()> {
        // Default implementation does nothing
        let _ = (view, context);
        Ok(())
    }
}

/// Trait for providing layouts and themes
///
/// This abstraction allows implementations to define their own layout
/// systems and theming approaches while maintaining compatibility.
pub trait LayoutProvider {
    /// The layout type this provider works with
    type Layout;

    /// The theme type for styling
    type Theme;

    /// The view type that layouts wrap
    type View;

    /// Get a layout by identifier
    ///
    /// # Arguments
    /// * `layout_id` - The layout identifier
    fn get_layout(&self, layout_id: &str) -> ComponentResult<Self::Layout>;

    /// Get a theme by identifier
    ///
    /// # Arguments
    /// * `theme_id` - The theme identifier
    fn get_theme(&self, theme_id: &str) -> ComponentResult<Self::Theme>;

    /// Apply a layout to a view
    ///
    /// # Arguments
    /// * `layout` - The layout to apply
    /// * `view` - The view to wrap
    /// * `theme` - The theme to apply
    /// * `language` - The language code
    fn apply_layout(
        &self,
        layout: &Self::Layout,
        view: Self::View,
        theme: &Self::Theme,
        language: &str,
    ) -> ComponentResult<Self::View>;

    /// Get the default layout
    fn default_layout(&self) -> ComponentResult<Self::Layout>;

    /// Get the default theme
    fn default_theme(&self) -> ComponentResult<Self::Theme>;
}

/// Trait for providing content and data
///
/// This abstraction allows different content sources (static files,
/// databases, APIs) to provide data to components in a consistent way.
pub trait ContentProvider {
    /// The content item type
    type ContentItem;

    /// The content collection type
    type ContentCollection;

    /// Query/filter type for content
    type Query;

    /// Get a single content item by identifier
    ///
    /// # Arguments
    /// * `content_id` - The content identifier
    /// * `language` - The language code
    fn get_content(&self, content_id: &str, language: &str) -> ComponentResult<Self::ContentItem>;

    /// Get a collection of content items
    ///
    /// # Arguments
    /// * `query` - Query/filter for the collection
    /// * `language` - The language code
    fn get_content_collection(
        &self,
        query: &Self::Query,
        language: &str,
    ) -> ComponentResult<Self::ContentCollection>;

    /// Check if content exists
    ///
    /// # Arguments
    /// * `content_id` - The content identifier
    /// * `language` - The language code
    fn has_content(&self, content_id: &str, language: &str) -> bool {
        self.get_content(content_id, language).is_ok()
    }

    /// List available content in a language
    ///
    /// # Arguments
    /// * `language` - The language code
    fn list_content(&self, language: &str) -> ComponentResult<Vec<String>>;
}

/// Trait for i18n and localization
///
/// This provides a consistent interface for internationalization
/// across different localization systems and content sources.
pub trait LocalizationProvider {
    /// Get a localized string
    ///
    /// # Arguments
    /// * `key` - The localization key
    /// * `language` - The language code
    /// * `args` - Arguments for string interpolation
    fn get_localized_string(
        &self,
        key: &str,
        language: &str,
        args: &HashMap<String, String>,
    ) -> ComponentResult<String>;

    /// Get available languages
    fn available_languages(&self) -> Vec<String>;

    /// Get the default language
    fn default_language(&self) -> String;

    /// Check if a language is supported
    ///
    /// # Arguments
    /// * `language` - The language code to check
    fn supports_language(&self, language: &str) -> bool {
        self.available_languages().contains(&language.to_string())
    }

    /// Get localized string with fallback to default language
    ///
    /// # Arguments
    /// * `key` - The localization key
    /// * `language` - The preferred language code
    /// * `args` - Arguments for string interpolation
    fn get_localized_string_with_fallback(
        &self,
        key: &str,
        language: &str,
        args: &HashMap<String, String>,
    ) -> ComponentResult<String> {
        // Try the requested language first
        if let Ok(result) = self.get_localized_string(key, language, args) {
            return Ok(result);
        }

        // Fallback to default language
        let default_lang = self.default_language();
        if language != default_lang {
            self.get_localized_string(key, &default_lang, args)
        } else {
            // If already trying default language, return key as fallback
            Ok(format!("[{}]", key))
        }
    }
}

/// Combined trait for complete component handling
///
/// This trait combines all the component-related capabilities for
/// implementations that want to provide a unified interface.
pub trait ComponentHandler {
    /// The component type
    type Component;

    /// The view type
    type View;

    /// The content type
    type Content;

    /// Properties/parameters
    type Props;

    /// Handle complete component rendering with all capabilities
    ///
    /// # Arguments
    /// * `component_id` - The component identifier
    /// * `props` - Component properties
    /// * `language` - The language code
    fn handle_component(
        &self,
        component_id: &str,
        props: Self::Props,
        language: &str,
    ) -> ComponentResult<Self::View>;

    /// Pre-load content for a component
    ///
    /// # Arguments
    /// * `component_id` - The component identifier
    /// * `language` - The language code
    fn preload_content(
        &self,
        component_id: &str,
        language: &str,
    ) -> ComponentResult<Self::Content> {
        // Default implementation returns an error
        let _ = (component_id, language);
        Err(ComponentError::ContentError(
            "Preloading not implemented".to_string(),
        ))
    }
}
