//! Server main entry point with trait-based dependency injection

use server_template::*;
use leptos::*;
use std::net::SocketAddr;

#[cfg(feature = "ssr")]
#[tokio::main]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
    use tracing_subscriber::{layer::SubscriberExt, util::SubscriberInitExt};

    // Initialize logging
    tracing_subscriber::registry()
        .with(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| "server_template=debug,tower_http=debug,axum::rejection=trace".into()),
        )
        .with(tracing_subscriber::fmt::layer())
        .init();

    // Load environment variables
    dotenvy::dotenv().ok();

    // Get configuration from environment
    let leptos_options = get_configuration(None).await?.leptos_options;
    let addr = leptos_options.site_addr;

    // Create mock providers - implementations will provide real ones
    let page_provider = MockPageProvider::new();
    let content_provider = MockContentProvider::new();
    let localization_provider = MockLocalizationProvider::new();
    let route_resolver = MockRouteResolver::new();

    // Create site configuration
    let site_config = SiteConfig {
        name: std::env::var("SITE_NAME").unwrap_or_else(|_| "Rustelo Site".to_string()),
        description: std::env::var("SITE_DESCRIPTION").unwrap_or_else(|_| "A Rustelo web application".to_string()),
        base_url: std::env::var("SITE_BASE_URL").unwrap_or_else(|_| "http://localhost:3000".to_string()),
        default_language: std::env::var("DEFAULT_LANGUAGE").unwrap_or_else(|_| "en".to_string()),
        languages: vec![], // Implementation should load from config
        default_theme: "default".to_string(),
        themes: vec![], // Implementation should load from config
        contact_email: std::env::var("CONTACT_EMAIL").ok(),
        metadata: std::collections::HashMap::new(),
    };

    // Create server state with dependency injection
    let server_state = ServerState::new(
        page_provider,
        content_provider,
        localization_provider,
        route_resolver,
        site_config,
        FrameworkConfig::default(),
    );

    // Build router with trait-based handlers
    let app = ServerBuilder::new()
        .state(server_state)
        .leptos_options(leptos_options)
        .build_router()?;

    let listener = tokio::net::TcpListener::bind(&addr).await?;
    tracing::info!("listening on http://{}", &addr);

    axum::serve(listener, app.into_make_service())
        .await
        .map_err(Into::into)
}

#[cfg(not(feature = "ssr"))]
pub fn main() {
    // This main function is required when compiling for WASM.
    // It doesn't need to do anything for the client build.
}

// Mock implementations for the template - real implementations will replace these
struct MockPageProvider;
struct MockContentProvider;
struct MockLocalizationProvider;
struct MockRouteResolver;

impl MockPageProvider {
    fn new() -> Self {
        Self
    }
}

impl MockContentProvider {
    fn new() -> Self {
        Self
    }
}

impl MockLocalizationProvider {
    fn new() -> Self {
        Self
    }
}

impl MockRouteResolver {
    fn new() -> Self {
        Self
    }
}

impl PageProvider for MockPageProvider {
    type Component = String;
    type View = String;
    type Props = ();

    fn get_component(&self, component_id: &str) -> ComponentResult<Self::Component> {
        // Mock implementation - real provider will load from files/database
        Ok(format!("component:{}", component_id))
    }

    fn render_component(
        &self,
        component: &Self::Component,
        _props: Self::Props,
        language: &str,
    ) -> ComponentResult<Self::View> {
        // Mock rendering - real provider will use Leptos components
        Ok(format!("<div data-component=\"{}\" data-lang=\"{}\">Mock Component</div>", component, language))
    }

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

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

    fn get_content(&self, content_id: &str, language: &str) -> ComponentResult<Self::ContentItem> {
        // Mock content - real provider will load from files/database
        Ok(format!("Content for {} in {}", content_id, language))
    }

    fn get_content_collection(
        &self,
        query: &Self::Query,
        language: &str,
    ) -> ComponentResult<Self::ContentCollection> {
        // Mock collection - real provider will query content
        Ok(vec![format!("Collection item for query '{}' in {}", query, language)])
    }

    fn list_content(&self, language: &str) -> ComponentResult<Vec<String>> {
        Ok(vec![
            format!("home-{}", language),
            format!("about-{}", language),
            format!("blog-post-1-{}", language),
        ])
    }
}

impl LocalizationProvider for MockLocalizationProvider {
    fn get_localized_string(
        &self,
        key: &str,
        language: &str,
        args: &std::collections::HashMap<String, String>,
    ) -> ComponentResult<String> {
        // Mock localization - real provider will load from .ftl files
        let base_text = match (key, language) {
            ("welcome", "en") => "Welcome",
            ("welcome", "es") => "Bienvenido",
            ("hello_name", "en") => "Hello, {name}",
            ("hello_name", "es") => "Hola, {name}",
            _ => return Err(ComponentError::ContentError(format!("Missing translation: {} for {}", key, language))),
        };

        // Simple template replacement
        let mut result = base_text.to_string();
        for (arg_key, arg_value) in args {
            result = result.replace(&format!("{{{}}}", arg_key), arg_value);
        }

        Ok(result)
    }

    fn available_languages(&self) -> Vec<String> {
        vec!["en".to_string(), "es".to_string()]
    }

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

impl RouteResolver for MockRouteResolver {
    type Component = String;
    type Parameters = std::collections::HashMap<String, String>;

    fn resolve_route(&self, path: &str) -> RoutingResult<RouteResolution<Self::Component, Self::Parameters>> {
        // Mock route resolution - real resolver will use routing configuration
        let (language, clean_path) = if path.starts_with("/es/") {
            ("es".to_string(), path.strip_prefix("/es").unwrap_or(path).to_string())
        } else {
            ("en".to_string(), path.to_string())
        };

        let component = match clean_path.as_str() {
            "/" => Some("home".to_string()),
            "/about" => Some("about".to_string()),
            "/contact" => Some("contact".to_string()),
            _ => None,
        };

        Ok(RouteResolution {
            component,
            path: clean_path,
            language: language.clone(),
            canonical_path: if language == "en" {
                clean_path.clone()
            } else {
                format!("/{}{}", language, clean_path)
            },
            parameters: std::collections::HashMap::new(),
            is_language_specific: language != "en",
        })
    }

    fn get_routes_for_language(&self, language: &str) -> RoutingResult<Vec<String>> {
        let base_routes = vec!["/", "/about", "/contact"];

        if language == "en" {
            Ok(base_routes.into_iter().map(|r| r.to_string()).collect())
        } else {
            Ok(base_routes.into_iter()
                .map(|r| format!("/{}{}", language, r))
                .collect())
        }
    }
}