//! Pure trait-based implementations for Rustelo
//!
//! This module provides PAP-compliant implementations using only configuration
//! objects and runtime resolution. No environment variables, no code
//! generation, no coupling.

use std::collections::HashMap;

use crate::{
    ComponentError, ComponentResult, ContentMetadata, ContentProvider, LanguageCode,
    LanguageDetector, LocalizationProvider, PageProvider, RouteInfo, RouteResolution,
    RouteResolver, RoutingError, RoutingResult, SiteConfig,
};

/// Parameters wrapper that implements AsRef<HashMap<String, String>>
#[derive(Debug, Clone, PartialEq)]
pub struct RouteParameters(HashMap<String, String>);

impl RouteParameters {
    pub fn new() -> Self {
        Self(HashMap::new())
    }

    pub fn insert(&mut self, key: String, value: String) {
        self.0.insert(key, value);
    }

    pub fn into_hashmap(self) -> HashMap<String, String> {
        self.0
    }
}

impl Default for RouteParameters {
    fn default() -> Self {
        Self::new()
    }
}

impl AsRef<HashMap<String, String>> for RouteParameters {
    fn as_ref(&self) -> &HashMap<String, String> {
        &self.0
    }
}

/// Pure trait-based route resolver using configuration objects only
pub struct DefaultRouteResolver {
    site_config: SiteConfig,
}

impl DefaultRouteResolver {
    pub fn new(site_config: SiteConfig) -> Self {
        Self { site_config }
    }

    pub fn from_defaults() -> Self {
        Self {
            site_config: SiteConfig::default(),
        }
    }
}

impl Default for DefaultRouteResolver {
    fn default() -> Self {
        Self::from_defaults()
    }
}

impl RouteResolver for DefaultRouteResolver {
    type Component = String;
    type Parameters = RouteParameters;

    fn resolve_route(
        &self,
        path: &str,
    ) -> RoutingResult<RouteResolution<Self::Component, Self::Parameters>> {
        // Pure configuration-based resolution
        let clean_path = path.trim_start_matches('/').trim_end_matches('/');
        let parameters = RouteParameters::new();

        // Simple route matching based on configuration
        let component = match clean_path {
            "" => "Home".to_string(),
            _ => "NotFound".to_string(),
        };

        Ok(RouteResolution {
            component: Some(component),
            path: path.to_string(),
            language: "en".to_string(),
            canonical_path: format!("/{}", clean_path),
            parameters,
            is_language_specific: false,
        })
    }

    fn get_routes_for_language(&self, _language: &str) -> RoutingResult<Vec<String>> {
        // Configuration-driven route list
        Ok(vec!["/".to_string()])
    }
}

/// Pure language detector using configuration
pub struct DefaultLanguageDetector {
    supported_languages: Vec<String>,
    default_language: String,
}

impl DefaultLanguageDetector {
    pub fn new(supported_languages: Vec<String>, default_language: String) -> Self {
        Self {
            supported_languages,
            default_language,
        }
    }

    pub fn from_defaults() -> Self {
        Self {
            supported_languages: vec!["en".to_string()],
            default_language: "en".to_string(),
        }
    }
}

impl Default for DefaultLanguageDetector {
    fn default() -> Self {
        Self::from_defaults()
    }
}

impl LanguageDetector for DefaultLanguageDetector {
    fn extract_language(&self, path: &str) -> (String, String) {
        let path = path.trim_start_matches('/');
        let parts: Vec<&str> = path.split('/').collect();

        if let Some(first_part) = parts.first() {
            if self.supported_languages.contains(&first_part.to_string()) {
                let remaining_path = if parts.len() > 1 {
                    format!("/{}", parts[1..].join("/"))
                } else {
                    "/".to_string()
                };
                return (first_part.to_string(), remaining_path);
            }
        }

        (self.default_language.clone(), format!("/{}", path))
    }

    fn supported_languages(&self) -> &[String] {
        &self.supported_languages
    }

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

/// Pure content provider using trait-based resolution
pub struct DefaultContentProvider;

impl Default for DefaultContentProvider {
    fn default() -> Self {
        Self::new()
    }
}

impl DefaultContentProvider {
    pub fn new() -> Self {
        Self
    }
}

impl ContentProvider for DefaultContentProvider {
    type ContentItem = ContentMetadata;
    type Query = String;
    type ContentCollection = Vec<ContentMetadata>;

    fn get_content(&self, content_id: &str, language: &str) -> ComponentResult<Self::ContentItem> {
        // Simple fallback content metadata
        Ok(ContentMetadata {
            id: content_id.to_string(),
            title: format!("{} Content", content_id),
            description: Some(format!("Content {} in {}", content_id, language)),
            author: Some("Author".to_string()),
            published_date: None,
            modified_date: None,
            tags: vec![],
            category: Some("general".to_string()),
            language: language.to_string(),
            content_type: "page".to_string(),
            is_published: true,
            is_featured: false,
            custom_fields: HashMap::new(),
        })
    }

    fn get_content_collection(
        &self,
        query: &Self::Query,
        _language: &str,
    ) -> ComponentResult<Self::ContentCollection> {
        // Return empty collection for now - pure trait implementation
        let _content_type = query;
        Ok(vec![])
    }

    fn list_content(&self, _language: &str) -> ComponentResult<Vec<String>> {
        // Return empty list for now - pure trait implementation
        Ok(vec![])
    }
}

/// Pure localization provider using configuration
pub struct DefaultLocalizationProvider {
    translations: HashMap<String, HashMap<String, String>>,
}

impl DefaultLocalizationProvider {
    pub fn new() -> Self {
        let mut translations = HashMap::new();

        // Basic English translations
        let mut en_translations = HashMap::new();
        en_translations.insert("home-title".to_string(), "Home".to_string());
        en_translations.insert("notfound-title".to_string(), "Not Found".to_string());
        translations.insert("en".to_string(), en_translations);

        Self { translations }
    }
}

impl Default for DefaultLocalizationProvider {
    fn default() -> Self {
        Self::new()
    }
}

impl LocalizationProvider for DefaultLocalizationProvider {
    fn get_localized_string(
        &self,
        key: &str,
        language: &str,
        _args: &HashMap<String, String>,
    ) -> ComponentResult<String> {
        if let Some(lang_translations) = self.translations.get(language) {
            if let Some(translation) = lang_translations.get(key) {
                return Ok(translation.clone());
            }
        }

        // Fallback to English
        if let Some(en_translations) = self.translations.get("en") {
            if let Some(translation) = en_translations.get(key) {
                return Ok(translation.clone());
            }
        }

        // Final fallback
        Ok(format!("[{}]", key))
    }

    fn available_languages(&self) -> Vec<String> {
        self.translations.keys().cloned().collect()
    }

    fn default_language(&self) -> String {
        "en".to_string()
    }
}

/// Pure page provider using trait-based rendering
pub struct DefaultPageProvider;

impl DefaultPageProvider {
    pub fn new() -> Self {
        Self
    }
}

impl Default for DefaultPageProvider {
    fn default() -> Self {
        Self::new()
    }
}

impl PageProvider for DefaultPageProvider {
    type Component = String;
    type View = String;
    type Props = HashMap<String, String>;

    fn get_component(&self, component_id: &str) -> ComponentResult<Self::Component> {
        Ok(component_id.to_string())
    }

    fn render_component(
        &self,
        component: &Self::Component,
        _props: Self::Props,
        language: &str,
    ) -> ComponentResult<Self::View> {
        // Simple HTML rendering based on component
        let html = match component.as_str() {
            "Home" => format!("<div class=\"home\"><h1>Welcome - {}</h1></div>", language),
            "NotFound" => format!(
                "<div class=\"not-found\"><h1>404 Not Found - {}</h1></div>",
                language
            ),
            _ => format!(
                "<div class=\"unknown\"><h1>Unknown Component: {} - {}</h1></div>",
                component, language
            ),
        };

        Ok(html)
    }

    fn list_components(&self) -> Vec<String> {
        vec!["Home".to_string(), "NotFound".to_string()]
    }
}

/// Combined application context with all providers
pub struct AppContext {
    pub route_resolver: DefaultRouteResolver,
    pub language_detector: DefaultLanguageDetector,
    pub content_provider: DefaultContentProvider,
    pub localization_provider: DefaultLocalizationProvider,
    pub page_provider: DefaultPageProvider,
}

impl AppContext {
    pub fn new() -> Self {
        Self {
            route_resolver: DefaultRouteResolver::default(),
            language_detector: DefaultLanguageDetector::default(),
            content_provider: DefaultContentProvider,
            localization_provider: DefaultLocalizationProvider::default(),
            page_provider: DefaultPageProvider,
        }
    }

    pub fn with_config(site_config: SiteConfig) -> Self {
        Self {
            route_resolver: DefaultRouteResolver::new(site_config),
            language_detector: DefaultLanguageDetector::default(),
            content_provider: DefaultContentProvider,
            localization_provider: DefaultLocalizationProvider::default(),
            page_provider: DefaultPageProvider,
        }
    }
}

impl Default for AppContext {
    fn default() -> Self {
        Self::new()
    }
}
