use rustelo_core_types::{
    BasicContentItem, ContentKindRegistry, RouteConfigToml, RoutesConfig,
};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

/// Example showing how to use core-types for validating TOML configuration
///
/// This demonstrates how core-types provides type safety and validation
/// for your configuration-driven Rustelo application.
fn main() -> Result<(), Box<dyn std::error::Error>> {
    println!("🔍 Core Types Configuration Validation Example");
    println!("==============================================");
    println!();
    println!("This example shows how TOML configuration gets validated");
    println!("through strongly-typed Rust structs.");
    println!();

    // Validate route configuration
    validate_route_configurations()?;

    // Validate content type configuration
    validate_content_type_configurations()?;

    // Validate content items
    validate_content_items()?;

    // Show serialization/deserialization
    demonstrate_serialization()?;

    println!("\n✅ Configuration validation demonstration complete!");
    println!("💡 Core-types ensures your TOML config is always valid at build time");
    Ok(())
}

/// Demonstrate route configuration validation
fn validate_route_configurations() -> Result<(), Box<dyn std::error::Error>> {
    println!("🛣️  Route Configuration Validation");
    println!("=================================");

    // Example of valid route configuration (what you'd put in site/config/routes/en.toml)
    let valid_routes = vec![
        RouteConfigToml {
            path: "/".to_string(),
            component: "Home".to_string(),
            language: "en".to_string(),
            title_key: "home-title".to_string(),
            description_key: Some("home-description".to_string()),
            enabled: true,
            priority: Some(1.0),
            keywords: Some(vec!["home".to_string(), "welcome".to_string()]),
            menu_group: Some("main".to_string()),
            menu_order: Some(1),
            show_in_sitemap: Some(true),
            raw_toml: "[routes]\npath = \"/\"\ncomponent = \"Home\"".to_string(),
            ..Default::default()
        },
        RouteConfigToml {
            path: "/about".to_string(),
            component: "About".to_string(),
            language: "en".to_string(),
            title_key: "about-title".to_string(),
            description_key: Some("about-description".to_string()),
            enabled: true,
            menu_group: Some("main".to_string()),
            menu_order: Some(2),
            raw_toml: "[routes]\npath = \"/about\"\ncomponent = \"About\"".to_string(),
            ..Default::default()
        },
    ];

    println!("✅ Validating good route configurations:");
    for route in &valid_routes {
        match route.validate() {
            Ok(()) => {
                println!("   ✅ {} -> {} (valid)", route.path, route.component);
                println!("      Title key: {}", route.title_key);
                println!("      Language: {}", route.language);
                println!("      Include in sitemap: {}", route.include_in_sitemap());
                println!("      Requires auth: {}", route.requires_authentication());
            }
            Err(e) => {
                println!("   ❌ {} -> Error: {}", route.path, e);
            }
        }
    }

    // Examples of invalid route configurations
    let invalid_routes = vec![
        RouteConfigToml {
            path: "about".to_string(), // Missing leading slash
            component: "About".to_string(),
            title_key: "about-title".to_string(),
            ..Default::default()
        },
        RouteConfigToml {
            path: "/services".to_string(),
            component: "".to_string(), // Empty component
            title_key: "services-title".to_string(),
            ..Default::default()
        },
        RouteConfigToml {
            path: "/contact".to_string(),
            component: "Contact".to_string(),
            title_key: "".to_string(), // Empty title key
            ..Default::default()
        },
    ];

    println!("\n❌ Validating invalid route configurations:");
    for route in &invalid_routes {
        match route.validate() {
            Ok(()) => {
                println!("   ⚠️  {} -> Unexpectedly valid!", route.path);
            }
            Err(e) => {
                println!("   ✅ {} -> Correctly caught error: {}", route.path, e);
            }
        }
    }

    // Create routes configuration and validate as a collection
    let routes_config = RoutesConfig {
        routes: valid_routes,
        settings: Some({
            let mut settings = HashMap::new();
            settings.insert("default_language".to_string(), "en".to_string());
            settings.insert("base_url".to_string(), "https://example.com".to_string());
            settings
        }),
    };

    println!("\n📊 Routes configuration summary:");
    println!("   Total routes: {}", routes_config.routes.len());
    println!("   Settings: {:?}", routes_config.settings);

    Ok(())
}

/// Demonstrate content type configuration validation
fn validate_content_type_configurations() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n📄 Content Type Configuration Validation");
    println!("========================================");

    // Example content configurations (from content-kinds.toml)
    let content_configs = vec![
        (
            "blog",
            ContentConfig {
                name: "blog".to_string(),
                title: "Blog Posts".to_string(),
                directory: "blog".to_string(),
                enabled: true,
                is_default: Some(false),
                specialized: None,
                features: ContentFeatures {
                    categories: true,
                    tags: true,
                    comments: true,
                    search: true,
                    archive: true,
                    ..Default::default()
                },
                icon: Some("📝".to_string()),
                color: Some("#3B82F6".to_string()),
                ..Default::default()
            },
        ),
        (
            "services",
            ContentConfig {
                name: "services".to_string(),
                title: "Services".to_string(),
                directory: "services".to_string(),
                enabled: true,
                is_default: Some(false),
                specialized: Some(vec!["pricing".to_string(), "testimonials".to_string()]),
                features: ContentFeatures {
                    categories: false,
                    tags: true,
                    comments: false,
                    search: true,
                    archive: false,
                    ..Default::default()
                },
                icon: Some("🛠️".to_string()),
                color: Some("#10B981".to_string()),
                ..Default::default()
            },
        ),
        (
            "page",
            ContentConfig {
                name: "page".to_string(),
                title: "Static Pages".to_string(),
                directory: "page".to_string(),
                enabled: true,
                is_default: Some(true),
                specialized: None,
                features: ContentFeatures::default(), // No special features
                icon: Some("📄".to_string()),
                color: Some("#6366F1".to_string()),
                ..Default::default()
            },
        ),
    ];

    println!("✅ Validating content type configurations:");
    let mut registry = ContentKindRegistry::new();

    for (name, config) in content_configs {
        match config.validate() {
            Ok(()) => {
                println!("   ✅ {} -> {}", name, config.title);
                println!("      Directory: {}", config.directory);
                println!("      Enabled: {}", config.enabled);
                println!("      Default: {}", config.is_default.unwrap_or(false));

                // Check features
                let features = vec!["categories", "tags", "comments", "search", "archive"];
                let enabled_features: Vec<_> =
                    features.iter().filter(|&f| config.has_feature(f)).collect();

                if !enabled_features.is_empty() {
                    println!("      Features: {:?}", enabled_features);
                }

                if let Some(ref specialized) = config.specialized {
                    println!("      Specialized: {:?}", specialized);
                }

                // Add to registry
                registry.register(name.to_string(), config);
            }
            Err(e) => {
                println!("   ❌ {} -> Error: {}", name, e);
            }
        }
    }

    println!("\n📊 Content registry summary:");
    println!("   Registered types: {}", registry.list_enabled().len());
    println!("   Default type: {:?}", registry.get_default());

    // Test invalid configurations
    let invalid_configs = vec![
        (
            "invalid1",
            ContentConfig {
                name: "".to_string(), // Empty name
                title: "Invalid Config".to_string(),
                directory: "invalid".to_string(),
                ..Default::default()
            },
        ),
        (
            "invalid2",
            ContentConfig {
                name: "invalid2".to_string(),
                title: "".to_string(), // Empty title
                directory: "invalid".to_string(),
                ..Default::default()
            },
        ),
        (
            "invalid3",
            ContentConfig {
                name: "invalid3".to_string(),
                title: "Invalid Config".to_string(),
                directory: "".to_string(), // Empty directory
                ..Default::default()
            },
        ),
    ];

    println!("\n❌ Validating invalid content configurations:");
    for (name, config) in invalid_configs {
        match config.validate() {
            Ok(()) => {
                println!("   ⚠️  {} -> Unexpectedly valid!", name);
            }
            Err(e) => {
                println!("   ✅ {} -> Correctly caught error: {}", name, e);
            }
        }
    }

    Ok(())
}

/// Demonstrate content item validation
fn validate_content_items() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n📝 Content Item Validation");
    println!("=========================");

    // Example content items (what gets loaded from markdown files)
    let content_items = vec![
        BasicContentItem {
            id: "blog-001".to_string(),
            title: "My First Blog Post".to_string(),
            slug: "my-first-blog-post".to_string(),
            content_type: "blog".to_string(),
            language: "en".to_string(),
            metadata: Metadata {
                description: Some("This is my first blog post about Rust".to_string()),
                keywords: vec![
                    "rust".to_string(),
                    "blog".to_string(),
                    "programming".to_string(),
                ],
                author: Some("John Doe".to_string()),
                category: Some("Programming".to_string()),
                tags: vec!["rust".to_string(), "web".to_string()],
                ..Default::default()
            },
            content: Some(
                "# My First Post\n\nThis is the content of my first blog post.".to_string(),
            ),
            html_content: Some(
                "<h1>My First Post</h1><p>This is the content of my first blog post.</p>"
                    .to_string(),
            ),
            published: true,
            created_at: Some("2024-01-01T12:00:00Z".to_string()),
            updated_at: Some("2024-01-02T10:30:00Z".to_string()),
        },
        BasicContentItem {
            id: "service-001".to_string(),
            title: "Web Development Services".to_string(),
            slug: "web-development".to_string(),
            content_type: "services".to_string(),
            language: "en".to_string(),
            metadata: Metadata {
                description: Some("Professional web development services".to_string()),
                keywords: vec![
                    "web".to_string(),
                    "development".to_string(),
                    "services".to_string(),
                ],
                price: Some("$2000".to_string()),
                duration: Some("4-6 weeks".to_string()),
                ..Default::default()
            },
            content: Some("# Web Development\n\nWe build modern web applications.".to_string()),
            html_content: Some(
                "<h1>Web Development</h1><p>We build modern web applications.</p>".to_string(),
            ),
            published: true,
            created_at: Some("2024-01-01T09:00:00Z".to_string()),
            updated_at: Some("2024-01-01T09:00:00Z".to_string()),
        },
        BasicContentItem {
            id: "page-001".to_string(),
            title: "About Us".to_string(),
            slug: "about".to_string(),
            content_type: "page".to_string(),
            language: "en".to_string(),
            metadata: Metadata {
                description: Some("Learn about our company and mission".to_string()),
                keywords: vec![
                    "about".to_string(),
                    "company".to_string(),
                    "mission".to_string(),
                ],
                ..Default::default()
            },
            content: Some(
                "# About Us\n\nWe are a technology company focused on innovation.".to_string(),
            ),
            html_content: Some(
                "<h1>About Us</h1><p>We are a technology company focused on innovation.</p>"
                    .to_string(),
            ),
            published: true,
            created_at: Some("2024-01-01T08:00:00Z".to_string()),
            updated_at: Some("2024-01-01T08:00:00Z".to_string()),
        },
    ];

    println!("✅ Processing content items:");
    for item in &content_items {
        println!("   📄 {} ({})", item.title, item.content_type);
        println!("      ID: {}", item.id);
        println!("      Slug: {}", item.slug);
        println!("      Language: {}", item.language);
        println!("      Published: {}", item.published);

        if let Some(ref description) = item.metadata.description {
            println!("      Description: {}", description);
        }

        if !item.metadata.keywords.is_empty() {
            println!("      Keywords: {:?}", item.metadata.keywords);
        }

        if let Some(ref author) = item.metadata.author {
            println!("      Author: {}", author);
        }

        if !item.metadata.tags.is_empty() {
            println!("      Tags: {:?}", item.metadata.tags);
        }

        if let Some(ref content) = item.content {
            println!("      Content length: {} chars", content.len());
        }

        if let Some(ref html) = item.html_content {
            println!("      HTML length: {} chars", html.len());
        }

        println!();
    }

    // Group by content type
    let mut by_type: HashMap<String, Vec<&BasicContentItem>> = HashMap::new();
    for item in &content_items {
        by_type
            .entry(item.content_type.clone())
            .or_default()
            .push(item);
    }

    println!("📊 Content summary by type:");
    for (content_type, items) in by_type {
        println!("   {}: {} items", content_type, items.len());
    }

    Ok(())
}

/// Demonstrate serialization and deserialization
fn demonstrate_serialization() -> Result<(), Box<dyn std::error::Error>> {
    println!("\n🔄 Serialization and Deserialization");
    println!("===================================");

    // Create a sample route configuration
    let original_config = RoutesConfig {
        routes: vec![RouteConfigToml {
            path: "/".to_string(),
            component: "Home".to_string(),
            language: "en".to_string(),
            title_key: "home-title".to_string(),
            description_key: Some("home-description".to_string()),
            enabled: true,
            raw_toml: "path = \"/\"\ncomponent = \"Home\"".to_string(),
            ..Default::default()
        }],
        settings: Some({
            let mut settings = HashMap::new();
            settings.insert("base_url".to_string(), "https://example.com".to_string());
            settings
        }),
    };

    println!("📝 Original configuration:");
    println!("   Routes: {}", original_config.routes.len());
    println!("   Settings: {:?}", original_config.settings);

    // Serialize to TOML
    println!("\n🔄 TOML Serialization:");
    match toml::to_string_pretty(&original_config) {
        Ok(toml_str) => {
            println!("   ✅ Serialized to TOML:");
            println!("   ```toml");
            for line in toml_str.lines().take(10) {
                // Show first 10 lines
                println!("   {}", line);
            }
            println!("   ```");

            // Deserialize back from TOML
            match toml::from_str::<RoutesConfig>(&toml_str) {
                Ok(deserialized) => {
                    println!("   ✅ Deserialized from TOML successfully");
                    println!(
                        "      Routes match: {}",
                        original_config.routes.len() == deserialized.routes.len()
                    );
                }
                Err(e) => {
                    println!("   ❌ Deserialization failed: {}", e);
                }
            }
        }
        Err(e) => {
            println!("   ❌ TOML serialization failed: {}", e);
        }
    }

    // Serialize to JSON (for API integration)
    println!("\n🔄 JSON Serialization:");
    match serde_json::to_string_pretty(&original_config) {
        Ok(json_str) => {
            println!("   ✅ Serialized to JSON:");
            println!("   ```json");
            for line in json_str.lines().take(10) {
                // Show first 10 lines
                println!("   {}", line);
            }
            println!("   ```");

            // Deserialize back from JSON
            match serde_json::from_str::<RoutesConfig>(&json_str) {
                Ok(deserialized) => {
                    println!("   ✅ Deserialized from JSON successfully");
                    println!(
                        "      Routes match: {}",
                        original_config.routes.len() == deserialized.routes.len()
                    );
                }
                Err(e) => {
                    println!("   ❌ JSON deserialization failed: {}", e);
                }
            }
        }
        Err(e) => {
            println!("   ❌ JSON serialization failed: {}", e);
        }
    }

    // Show format conversion utility
    println!("\n🔄 Format Conversion:");
    let sample_toml = r#"
[[routes]]
path = "/about"
component = "About"
language = "en"
title_key = "about-title"
enabled = true

[settings]
base_url = "https://example.com"
default_language = "en"
"#;

    match convert_toml_to_json(sample_toml) {
        Ok(json) => {
            println!("   ✅ Converted TOML to JSON:");
            println!("   ```json");
            for line in json.lines().take(8) {
                // Show first 8 lines
                println!("   {}", line);
            }
            println!("   ```");
        }
        Err(e) => {
            println!("   ❌ Conversion failed: {}", e);
        }
    }

    Ok(())
}

/// Utility function to convert TOML to JSON
fn convert_toml_to_json(toml_content: &str) -> Result<String, Box<dyn std::error::Error>> {
    let routes: RoutesConfig = toml::from_str(toml_content)?;
    let json = serde_json::to_string_pretty(&routes)?;
    Ok(json)
}

// Default implementations for demonstration
impl Default for RouteConfigToml {
    fn default() -> Self {
        Self {
            path: String::new(),
            component: String::new(),
            language: "en".to_string(),
            content_type: None,
            title: None,
            description: None,
            title_key: String::new(),
            description_key: None,
            enabled: true,
            priority: None,
            keywords: None,
            menu_group: None,
            menu_order: None,
            menu_icon: None,
            is_external: None,
            requires_auth: None,
            show_in_sitemap: None,
            alternate_paths: None,
            canonical_path: None,
            props: None,
            unified_component: None,
            lang_prefixes: None,
            params_component: None,
            raw_toml: String::new(),
        }
    }
}

impl Default for ContentConfig {
    fn default() -> Self {
        Self {
            name: String::new(),
            title: String::new(),
            directory: String::new(),
            enabled: true,
            is_default: None,
            specialized: None,
            features: ContentFeatures::default(),
            icon: None,
            color: None,
        }
    }
}

impl Default for ContentFeatures {
    fn default() -> Self {
        Self {
            categories: false,
            tags: false,
            comments: false,
            search: false,
            archive: false,
        }
    }
}

impl Default for Metadata {
    fn default() -> Self {
        Self {
            description: None,
            keywords: Vec::new(),
            author: None,
            category: None,
            tags: Vec::new(),
            price: None,
            duration: None,
        }
    }
}

// Mock implementations for demonstration
impl RouteConfigToml {
    fn validate(&self) -> Result<(), String> {
        if self.path.is_empty() {
            return Err("Path cannot be empty".to_string());
        }

        if !self.path.starts_with('/') {
            return Err("Path must start with '/'".to_string());
        }

        if self.component.is_empty() {
            return Err("Component cannot be empty".to_string());
        }

        if self.title_key.is_empty() {
            return Err("Title key cannot be empty".to_string());
        }

        Ok(())
    }

    fn include_in_sitemap(&self) -> bool {
        self.show_in_sitemap.unwrap_or(true) && self.enabled
    }

    fn requires_authentication(&self) -> bool {
        self.requires_auth.unwrap_or(false)
    }
}

impl ContentConfig {
    fn validate(&self) -> Result<(), String> {
        if self.name.is_empty() {
            return Err("Name cannot be empty".to_string());
        }

        if self.title.is_empty() {
            return Err("Title cannot be empty".to_string());
        }

        if self.directory.is_empty() {
            return Err("Directory cannot be empty".to_string());
        }

        Ok(())
    }

    fn has_feature(&self, feature: &str) -> bool {
        match feature {
            "categories" => self.features.categories,
            "tags" => self.features.tags,
            "comments" => self.features.comments,
            "search" => self.features.search,
            "archive" => self.features.archive,
            _ => false,
        }
    }
}

impl ContentKindRegistry {
    fn new() -> Self {
        Self {
            configs: HashMap::new(),
        }
    }

    fn register(&mut self, name: String, config: ContentConfig) {
        self.configs.insert(name, config);
    }

    fn list_enabled(&self) -> Vec<&ContentConfig> {
        self.configs.values().filter(|c| c.enabled).collect()
    }

    fn get_default(&self) -> Option<&ContentConfig> {
        self.configs
            .values()
            .find(|c| c.is_default.unwrap_or(false))
    }
}

// Mock trait implementations for serialization demonstration
use serde::{Deserialize, Serialize};

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ContentConfig {
    name: String,
    title: String,
    directory: String,
    enabled: bool,
    is_default: Option<bool>,
    specialized: Option<Vec<String>>,
    features: ContentFeatures,
    icon: Option<String>,
    color: Option<String>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct ContentFeatures {
    categories: bool,
    tags: bool,
    comments: bool,
    search: bool,
    archive: bool,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
struct Metadata {
    description: Option<String>,
    keywords: Vec<String>,
    author: Option<String>,
    category: Option<String>,
    tags: Vec<String>,
    price: Option<String>,
    duration: Option<String>,
}

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

    #[test]
    fn test_route_validation() {
        let valid_route = RouteConfigToml {
            path: "/about".to_string(),
            component: "About".to_string(),
            title_key: "about-title".to_string(),
            ..Default::default()
        };

        assert!(valid_route.validate().is_ok());

        let invalid_route = RouteConfigToml {
            path: "about".to_string(), // Missing leading slash
            component: "".to_string(), // Empty component
            ..Default::default()
        };

        assert!(invalid_route.validate().is_err());
    }

    #[test]
    fn test_content_config_features() {
        let config = ContentConfig {
            name: "blog".to_string(),
            title: "Blog".to_string(),
            directory: "blog".to_string(),
            features: ContentFeatures {
                categories: true,
                tags: true,
                comments: false,
                search: true,
                archive: false,
            },
            ..Default::default()
        };

        assert!(config.has_feature("categories"));
        assert!(config.has_feature("tags"));
        assert!(!config.has_feature("comments"));
        assert!(config.has_feature("search"));
        assert!(!config.has_feature("archive"));
        assert!(!config.has_feature("unknown"));
    }

    #[test]
    fn test_serialization() {
        let config = RoutesConfig {
            routes: vec![RouteConfigToml {
                path: "/test".to_string(),
                component: "Test".to_string(),
                title_key: "test-title".to_string(),
                ..Default::default()
            }],
            settings: None,
        };

        // Test JSON serialization
        let json = serde_json::to_string(&config).unwrap();
        let deserialized: RoutesConfig = serde_json::from_str(&json).unwrap();

        assert_eq!(config.routes.len(), deserialized.routes.len());
        assert_eq!(config.routes[0].path, deserialized.routes[0].path);
    }
}
