//! Template integration example for Rustelo
//!
//! This example shows how to integrate the template system with your Rustelo
//! application.

use std::sync::Arc;

use axum::{
    extract::{Path, State},
    http::StatusCode,
    response::Html,
    routing::get,
    Router,
};
use tokio;
use tracing::{info, Level};
use tracing_subscriber;

use crate::template::{TemplateConfig, TemplateService};

/// Application state containing the template service
#[derive(Clone)]
#[allow(dead_code)]
pub struct AppState {
    pub template_service: Arc<TemplateService>,
}

/// Initialize the template service
#[allow(dead_code)]
pub async fn initialize_template_service(
) -> Result<Arc<TemplateService>, Box<dyn std::error::Error>> {
    // Create template configuration
    let content_config = rustelo_core_lib::config::ContentConfig::from_env();
    let config = TemplateConfig::new(
        content_config.templates_path.to_string_lossy().as_ref(),
        content_config
            .root_path
            .join("docs")
            .to_string_lossy()
            .as_ref(),
    )
    .with_cache(true)
    .with_extension("html");

    // Create template service
    let template_service = TemplateService::with_config(config)?
        .with_languages(vec!["en".to_string(), "es".to_string(), "fr".to_string()])
        .with_default_language("en")
        .with_cache(true);

    info!("Template service initialized successfully");
    info!(
        "Available languages: {:?}",
        template_service.get_available_languages()
    );
    info!(
        "Default language: {}",
        template_service.get_default_language()
    );

    // Preload templates for better performance
    let service_clone = template_service.clone();
    tokio::spawn(async move {
        if let Err(e) = service_clone.preload_language("en").await {
            eprintln!("Warning: Failed to preload English templates: {}", e);
        }
        if let Err(e) = service_clone.preload_language("es").await {
            eprintln!("Warning: Failed to preload Spanish templates: {}", e);
        }
    });

    Ok(Arc::new(template_service))
}

/// Home page handler
#[allow(dead_code)]
pub async fn home_handler(State(state): State<AppState>) -> Result<Html<String>, StatusCode> {
    // This could render a home page template
    let html = r#"
    <!DOCTYPE html>
    <html>
    <head>
        <title>Rustelo Template System</title>
        <style>
            body { font-family: Arial, sans-serif; max-width: 800px; margin: 0 auto; padding: 20px; }
            h1 { color: #333; }
            .nav { margin: 20px 0; }
            .nav a { display: inline-block; margin-right: 20px; padding: 10px 15px; background: #007bff; color: white; text-decoration: none; border-radius: 5px; }
            .nav a:hover { background: #0056b3; }
        </style>
    </head>
    <body>
        <h1>Welcome to Rustelo Template System</h1>
        <p>This is a demo of the Rustelo template system with localization support.</p>

        <div class="nav">
            <h2>Sample Pages</h2>
            <a href="/page:getting-started?lang=en">Getting Started (English)</a>
            <a href="/page:getting-started?lang=es">Getting Started (Spanish)</a>
            <a href="/page:about?lang=en">About (English)</a>
            <a href="/page:about?lang=es">About (Spanish)</a>
        </div>

        <div class="nav">
            <h2>API Examples</h2>
            <a href="/api/template/languages">Available Languages</a>
            <a href="/api/template/list/en">English Content</a>
            <a href="/api/template/list/es">Spanish Content</a>
            <a href="/api/template/stats">Template Stats</a>
            <a href="/api/template/health">Health Check</a>
        </div>
    </body>
    </html>
    "#;

    Ok(Html(html.to_string()))
}

/// Language selector handler
#[allow(dead_code)]
pub async fn language_selector(State(state): State<AppState>) -> Result<Html<String>, StatusCode> {
    let languages = state.template_service.get_available_languages();

    let mut html = String::from(
        r#"
    <!DOCTYPE html>
    <html>
    <head>
        <title>Language Selector</title>
        <style>
            body { font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto; padding: 20px; }
            .lang-button { display: block; margin: 10px 0; padding: 15px; background: #28a745; color: white; text-decoration: none; border-radius: 5px; text-align: center; }
            .lang-button:hover { background: #218838; }
        </style>
    </head>
    <body>
        <h1>Choose Your Language</h1>
        <p>Select a language to view the getting started guide:</p>
    "#,
    );

    for lang in languages {
        html.push_str(&format!(
            r#"<a href="/page:getting-started?lang={}" class="lang-button">{} - Getting Started</a>"#,
            lang,
            match lang.as_str() {
                "en" => "English",
                "es" => "Español",
                "fr" => "Français",
                _ => &lang,
            }
        ));
    }

    html.push_str(
        r#"
        <p><a href="/">← Back to Home</a></p>
    </body>
    </html>
    "#,
    );

    Ok(Html(html))
}

/// Create application router with template integration
#[allow(dead_code)]
pub fn create_app_router(template_service: Arc<TemplateService>) -> Router {
    let state = AppState {
        template_service: template_service.clone(),
    };

    Router::new()
        // Home page
        .route("/", get(home_handler))
        .route("/languages", get(language_selector))
        // Add basic template routes manually to avoid state type conflicts
        .route("/page/:content_name", get(basic_template_handler))
        .with_state(state)
}

/// Basic template handler that avoids state type conflicts
#[allow(dead_code)]
async fn basic_template_handler(
    State(state): State<AppState>,
    Path(content_name): Path<String>,
) -> Result<Html<String>, StatusCode> {
    // Simple template rendering without complex integration
    let content = format!(
        r#"
        <html>
        <head><title>{}</title></head>
        <body>
            <h1>Template: {}</h1>
            <p>This is a basic template handler for the example.</p>
            <p>In a real implementation, this would use the template service to render content.</p>
            <a href="/">Back to Home</a>
        </body>
        </html>
        "#,
        content_name, content_name
    );
    Ok(Html(content))
}

/// Main function to run the example
#[allow(dead_code)]
pub async fn run_example() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize tracing
    tracing_subscriber::fmt().with_max_level(Level::INFO).init();

    info!("Starting Rustelo Template System Example");

    // Initialize template service
    let template_service = initialize_template_service().await?;

    // Create router
    let app = create_app_router(template_service);

    // Create listener
    let listener = tokio::net::TcpListener::bind("127.0.0.1:3030").await?;
    info!("Server running on http://127.0.0.1:3030");

    // Run server
    axum::serve(listener, app).await?;

    Ok(())
}

/// Example of programmatic template rendering
#[allow(dead_code)]
pub async fn example_programmatic_rendering() -> Result<(), Box<dyn std::error::Error>> {
    // Initialize template service
    let template_service = initialize_template_service().await?;

    // Example 1: Render a specific page
    match template_service.render_page("getting-started", "en").await {
        Ok(rendered) => {
            println!("Successfully rendered page:");
            println!("Template: {}", rendered.config.template_name);
            println!("Content length: {} bytes", rendered.content.len());
        }
        Err(e) => {
            eprintln!("Failed to render page: {}", e);
        }
    }

    // Example 2: List available content
    match template_service.get_available_content("en").await {
        Ok(content_list) => {
            println!("Available English content:");
            for content in content_list {
                println!("  - {}", content);
            }
        }
        Err(e) => {
            eprintln!("Failed to list content: {}", e);
        }
    }

    // Example 3: Check if page exists
    let exists = template_service.page_exists("getting-started", "en");
    println!("Page 'getting-started' exists in English: {}", exists);

    // Example 4: Get page configuration
    match template_service
        .get_page_config("getting-started", "en")
        .await
    {
        Ok(config) => {
            println!("Page configuration:");
            println!("  Template: {}", config.template_name);
            println!("  Values: {} items", config.values.len());
            if let Some(title) = config.values.get("title") {
                println!("  Title: {}", title);
            }
        }
        Err(e) => {
            eprintln!("Failed to get page config: {}", e);
        }
    }

    // Example 5: Custom template rendering
    let mut custom_values = std::collections::HashMap::new();
    custom_values.insert(
        "title".to_string(),
        serde_json::Value::String("Custom Title".to_string()),
    );
    custom_values.insert(
        "content".to_string(),
        serde_json::Value::String("Custom content".to_string()),
    );

    match template_service
        .render_with_context("page", custom_values)
        .await
    {
        Ok(rendered_html) => {
            println!("Custom template rendered successfully");
            println!("HTML length: {} bytes", rendered_html.len());
        }
        Err(e) => {
            eprintln!("Failed to render custom template: {}", e);
        }
    }

    Ok(())
}

/// Example of adding custom filters and functions
#[allow(dead_code)]
pub async fn example_custom_filters() -> Result<(), Box<dyn std::error::Error>> {
    let template_service = initialize_template_service().await?;

    // Add custom filter
    template_service.add_filter(
        "uppercase",
        |value: &serde_json::Value, _: &std::collections::HashMap<String, serde_json::Value>| {
            let text = value.as_str().unwrap_or("");
            Ok(serde_json::Value::String(text.to_uppercase()))
        },
    )?;

    // Add custom function
    template_service.add_function(
        "current_timestamp",
        |_: &std::collections::HashMap<String, serde_json::Value>| {
            let timestamp = std::time::SystemTime::now()
                .duration_since(std::time::UNIX_EPOCH)
                .unwrap()
                .as_secs();
            Ok(serde_json::Value::Number(timestamp.into()))
        },
    )?;

    info!("Custom filters and functions added successfully");

    Ok(())
}

/// Example of template service monitoring
#[allow(dead_code)]
pub async fn example_monitoring() -> Result<(), Box<dyn std::error::Error>> {
    let template_service = initialize_template_service().await?;

    // Get service statistics
    let stats = template_service.get_engine_stats();
    println!("Template Service Statistics:");
    for (key, value) in stats {
        println!("  {}: {}", key, value);
    }

    // Monitor template rendering
    let start_time = std::time::Instant::now();
    match template_service.render_page("getting-started", "en").await {
        Ok(_) => {
            let duration = start_time.elapsed();
            println!("Page rendered in {:?}", duration);
        }
        Err(e) => {
            eprintln!("Rendering failed: {}", e);
        }
    }

    Ok(())
}

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

    #[tokio::test]
    async fn test_template_service_initialization() {
        let result = initialize_template_service().await;
        assert!(result.is_ok());

        let service = result.unwrap();
        assert_eq!(service.get_default_language(), "en");
        assert!(service
            .get_available_languages()
            .contains(&"en".to_string()));
    }

    #[tokio::test]
    async fn test_programmatic_rendering() {
        let result = example_programmatic_rendering().await;
        // This test might fail if template files don't exist, which is okay for demo
        println!("Programmatic rendering test result: {:?}", result);
    }

    #[tokio::test]
    async fn test_custom_filters() {
        let result = example_custom_filters().await;
        assert!(result.is_ok());
    }

    #[tokio::test]
    async fn test_monitoring() {
        let result = example_monitoring().await;
        println!("Monitoring test result: {:?}", result);
    }
}
