use std::collections::HashMap;
use std::fs;
use std::path::Path;

use serde::{Deserialize, Serialize};

use crate::build::build_tasks::route_generation::load_routes_config;
use crate::utils::RouteMetadataAccess;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentKindConfig {
    pub name: String,
    pub directory: String,
    pub enabled: bool,
    pub is_default: Option<bool>,
    pub specialized: Option<bool>,
    pub features: ContentFeatures,
}

// TODO: ARCHITECTURAL DEBT - ContentFeatures should be in a separate config
// crate Currently duplicated here due to circular dependency: codegen generates
// code for shared This is a minimal copy for TOML deserialization only
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentFeatures {
    pub style_mode: String,
    pub style_css: String,
    pub use_feature: bool,
    pub use_categories: bool,
    pub use_tags: bool,
    pub use_emojis: bool,
    pub cta_view: String,
    // Pagination features
    pub default_page_size: Option<u32>,
    pub page_size_options: Option<Vec<u32>>,
    pub show_page_info: Option<bool>,
    pub pagination_style: Option<String>,
    // Optional specialized features
    pub show_difficulty: Option<bool>,
    pub show_duration: Option<bool>,
    pub show_prerequisites: Option<bool>,
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ContentKindsConfig {
    pub content_kinds: Vec<ContentKindConfig>,
}

pub fn generate_content_types(content_root: &str, out_dir: &str) -> Result<(), String> {
    // 1. Read SITE_SERVER_ROOT_CONTENT/content-kinds.toml (content_root should be
    //    the content directory)
    let config_path = Path::new(content_root).join("content-kinds.toml");

    if !config_path.exists() {
        return Err(format!(
            "Content kinds config not found at: {}",
            config_path.display()
        ));
    }

    let config_content = fs::read_to_string(&config_path)
        .map_err(|e| format!("Failed to read config file: {}", e))?;

    let config: ContentKindsConfig = toml::from_str(&config_content)
        .map_err(|e| format!("Failed to parse config TOML: {}", e))?;

    // 2. Generate Rust code
    let mut code = String::new();

    // Add imports and dependencies
    code.push_str("// Generated code - do not edit manually\n");
    code.push_str("// This file is generated from content_root/content/content-kinds.toml\n\n");
    code.push_str("use leptos::prelude::*;\n");
    code.push_str("use serde::{Deserialize, Serialize};\n");
    code.push_str("use std::collections::HashMap;\n");
    code.push_str("use crate::content::traits::*;\n");
    code.push_str(
        "use crate::content::{UnifiedContentItem, ContentItemTrait, ContentKindRegistry, \
         ContentConfig, ContentFeatures};\n\n",
    );

    // Generate ContentKind enum (exclude specialized content for now)
    code.push_str("#[derive(Debug, Clone, Serialize, Deserialize)]\n");
    code.push_str("pub enum ContentKind {\n");

    for kind in &config.content_kinds {
        if kind.is_default == Some(true) {
            code.push_str("    Content(UnifiedContentItem),  // Base unified content type\n");
        } else if kind.specialized != Some(true) {
            // Only include non-specialized content
            code.push_str(&format!(
                "    {}(UnifiedContentItem),  // Using unified content system\n",
                capitalize(&kind.name)
            ));
        }
        // Skip specialized content for now due to serialization issues
    }
    code.push_str("}\n\n");

    // Note: We no longer generate individual content structs as we use
    // UnifiedContentItem All content types are now handled by the unified
    // content system
    code.push_str("// All content types now use UnifiedContentItem from crate::content::item\n");
    code.push_str("// Individual structs are no longer needed due to unified architecture\n\n");

    // Generate ContentKindRegistry initialization
    code.push_str("pub fn create_content_kind_registry() -> ContentKindRegistry {\n");
    code.push_str("    let mut registry = ContentKindRegistry::new();\n");
    code.push_str("    \n");
    code.push_str("    #[cfg(target_arch = \"wasm32\")]\n");
    code.push_str("    {\n");
    code.push_str(
        "        // WASM: Register all enabled content types without filesystem checks\n",
    );
    code.push_str(
        "        // The content files are embedded at build time, so we can register statically\n",
    );
    for kind in &config.content_kinds {
        if kind.enabled {
            code.push_str("        registry.register(ContentConfig {\n");
            code.push_str(&format!(
                "            name: \"{}\".to_string(),\n",
                kind.name
            ));
            code.push_str(&format!(
                "            directory: \"{}\".to_string(),\n",
                kind.directory
            ));
            code.push_str(&format!("            enabled: {},\n", kind.enabled));
            code.push_str(&format!("            is_default: {:?},\n", kind.is_default));
            code.push_str(&format!(
                "            specialized: {:?},\n",
                kind.specialized
            ));
            code.push_str("            features: ContentFeatures {\n");
            code.push_str(&format!(
                "                style_mode: \"{}\".to_string(),\n",
                kind.features.style_mode
            ));
            code.push_str(&format!(
                "                style_css: \"{}\".to_string(),\n",
                kind.features.style_css
            ));
            code.push_str(&format!(
                "                use_feature: {},\n",
                kind.features.use_feature
            ));
            code.push_str(&format!(
                "                use_categories: {},\n",
                kind.features.use_categories
            ));
            code.push_str(&format!(
                "                use_tags: {},\n",
                kind.features.use_tags
            ));
            code.push_str(&format!(
                "                use_emojis: {},\n",
                kind.features.use_emojis
            ));
            code.push_str(&format!(
                "                cta_view: \"{}\".to_string(),\n",
                kind.features.cta_view
            ));
            code.push_str(&format!(
                "                default_page_size: {:?},\n",
                kind.features.default_page_size
            ));
            if let Some(ref options) = kind.features.page_size_options {
                code.push_str(&format!(
                    "                page_size_options: Some(vec!{:?}),\n",
                    options
                ));
            } else {
                code.push_str("                page_size_options: None,\n");
            }
            code.push_str(&format!(
                "                show_page_info: {:?},\n",
                kind.features.show_page_info
            ));
            if let Some(ref style) = kind.features.pagination_style {
                code.push_str(&format!(
                    "                pagination_style: Some(\"{}\".to_string()),\n",
                    style
                ));
            } else {
                code.push_str("                pagination_style: None,\n");
            }
            code.push_str(&format!(
                "                show_difficulty: {:?},\n",
                kind.features.show_difficulty
            ));
            code.push_str(&format!(
                "                show_duration: {:?},\n",
                kind.features.show_duration
            ));
            code.push_str(&format!(
                "                show_prerequisites: {:?},\n",
                kind.features.show_prerequisites
            ));
            code.push_str("            },\n");
            code.push_str("        });\n");
            code.push_str(&format!(
                "        tracing::debug!(\"WASM: Registered content type '{}' statically\");\n",
                kind.name
            ));
        }
    }
    code.push_str("    }\n");
    code.push_str("    #[cfg(not(target_arch = \"wasm32\"))]\n");
    code.push_str("    {\n");
    code.push_str("        // Server: Check filesystem for existing directories\n");
    code.push_str("        let content_root = {\n");
    code.push_str(
        "            let public_path = std::env::var(\"SITE_PUBLIC_PATH\").unwrap_or_else(|_| \
         \"public\".to_string());\n",
    );
    code.push_str(
        "            let server_root_content = \
         std::env::var(\"SITE_SERVER_ROOT_CONTENT\").unwrap_or_else(|_| \"r\".to_string());\n",
    );
    code.push_str("            format!(\"{}/{}\", public_path, server_root_content)\n");
    code.push_str("        };\n");

    for kind in &config.content_kinds {
        code.push_str(&format!(
            "        // Check if directory exists for content type '{}'\n",
            kind.name
        ));
        code.push_str(&format!(
            "        if std::path::Path::new(&content_root).join(\"{}\").exists() {{\n",
            kind.directory
        ));
        code.push_str("            registry.register(ContentConfig {\n");
        code.push_str(&format!(
            "                name: \"{}\".to_string(),\n",
            kind.name
        ));
        code.push_str(&format!(
            "                directory: \"{}\".to_string(),\n",
            kind.directory
        ));
        code.push_str(&format!("                enabled: {},\n", kind.enabled));
        code.push_str(&format!(
            "                is_default: {:?},\n",
            kind.is_default
        ));
        code.push_str(&format!(
            "                specialized: {:?},\n",
            kind.specialized
        ));
        code.push_str("                features: ContentFeatures {\n");
        code.push_str(&format!(
            "                    style_mode: \"{}\".to_string(),\n",
            kind.features.style_mode
        ));
        code.push_str(&format!(
            "                    style_css: \"{}\".to_string(),\n",
            kind.features.style_css
        ));
        code.push_str(&format!(
            "                    use_feature: {},\n",
            kind.features.use_feature
        ));
        code.push_str(&format!(
            "                    use_categories: {},\n",
            kind.features.use_categories
        ));
        code.push_str(&format!(
            "                    use_tags: {},\n",
            kind.features.use_tags
        ));
        code.push_str(&format!(
            "                    use_emojis: {},\n",
            kind.features.use_emojis
        ));
        code.push_str(&format!(
            "                    cta_view: \"{}\".to_string(),\n",
            kind.features.cta_view
        ));
        code.push_str(&format!(
            "                    default_page_size: {:?},\n",
            kind.features.default_page_size
        ));
        if let Some(ref options) = kind.features.page_size_options {
            code.push_str(&format!(
                "                    page_size_options: Some(vec!{:?}),\n",
                options
            ));
        } else {
            code.push_str("                    page_size_options: None,\n");
        }
        code.push_str(&format!(
            "                    show_page_info: {:?},\n",
            kind.features.show_page_info
        ));
        if let Some(ref style) = kind.features.pagination_style {
            code.push_str(&format!(
                "                    pagination_style: Some(\"{}\".to_string()),\n",
                style
            ));
        } else {
            code.push_str("                    pagination_style: None,\n");
        }
        code.push_str(&format!(
            "                    show_difficulty: {:?},\n",
            kind.features.show_difficulty
        ));
        code.push_str(&format!(
            "                    show_duration: {:?},\n",
            kind.features.show_duration
        ));
        code.push_str(&format!(
            "                    show_prerequisites: {:?},\n",
            kind.features.show_prerequisites
        ));
        code.push_str("                },\n");
        code.push_str("            });\n");
        code.push_str(&format!(
            "            tracing::debug!(\"SERVER: Registered content type '{}' with directory \
             '{{}}/{}'\", content_root);\n",
            kind.name, kind.directory
        ));
        code.push_str("        } else {\n");
        code.push_str(&format!(
            "            tracing::warn!(\"SERVER: Content type '{}' enabled in content-kinds.toml \
             but directory '{{}}/{}' does not exist - SKIPPING registration\", content_root);\n",
            kind.name, kind.directory
        ));
        code.push_str("        }\n");
    }
    code.push_str("    }\n");
    code.push_str("    \n");
    code.push_str("    registry\n");
    code.push_str("}\n\n");

    // Generate content kind constants
    code.push_str("// Content kind constants\n");
    for kind in &config.content_kinds {
        code.push_str(&format!(
            "pub const {}_KIND: &str = \"{}\";\n",
            kind.name.to_uppercase(),
            kind.name
        ));
    }
    code.push('\n');

    // Generate helper functions
    code.push_str("pub fn get_enabled_kinds() -> Vec<&'static str> {\n");
    code.push_str("    vec![\n");
    for kind in &config.content_kinds {
        if kind.enabled {
            code.push_str(&format!("        \"{}\",\n", kind.name));
        }
    }
    code.push_str("    ]\n");
    code.push_str("}\n\n");

    // Generate utility functions used by other modules
    code.push_str("pub fn get_all_content_types() -> Vec<&'static str> {\n");
    code.push_str("    #[cfg(target_arch = \"wasm32\")]\n");
    code.push_str("    {\n");
    code.push_str(
        "        // WASM: Return enabled content types statically (no filesystem access)\n",
    );
    code.push_str("        vec![\n");
    for kind in &config.content_kinds {
        if kind.enabled {
            code.push_str(&format!("            \"{}\",\n", kind.name));
        }
    }
    code.push_str("        ]\n");
    code.push_str("    }\n");
    code.push_str("    #[cfg(not(target_arch = \"wasm32\"))]\n");
    code.push_str("    {\n");
    code.push_str("        // Server: Check filesystem for existing directories\n");
    code.push_str("        let content_root = {\n");
    code.push_str(
        "            let public_path = std::env::var(\"SITE_PUBLIC_PATH\").unwrap_or_else(|_| \
         \"public\".to_string());\n",
    );
    code.push_str(
        "            let server_root_content = \
         std::env::var(\"SITE_SERVER_ROOT_CONTENT\").unwrap_or_else(|_| \"r\".to_string());\n",
    );
    code.push_str("            format!(\"{}/{}\", public_path, server_root_content)\n");
    code.push_str("        };\n");
    code.push_str("        let mut types = Vec::new();\n");
    for kind in &config.content_kinds {
        code.push_str("        // Only include content types with existing directories\n");
        code.push_str(&format!(
            "        if std::path::Path::new(&content_root).join(\"{}\").exists() {{\n",
            kind.directory
        ));
        code.push_str(&format!("            types.push(\"{}\");\n", kind.name));
        code.push_str("        }\n");
    }
    code.push_str("        types\n");
    code.push_str("    }\n");
    code.push_str("}\n\n");

    // Extract component mappings from actual routes configuration
    let component_to_content_type =
        extract_component_mappings_from_routes(content_root, &config.content_kinds);

    code.push_str("pub fn get_content_type_from_component(component: &str) -> Option<String> {\n");
    code.push_str("    match component {\n");

    // Generate mappings from discovered routes
    for (component_name, content_type) in &component_to_content_type {
        code.push_str(&format!(
            "        \"{}\" => Some(\"{}\".to_string()),\n",
            component_name, content_type
        ));
    }

    code.push_str("        _ => None,\n");
    code.push_str("    }\n");
    code.push_str("}\n\n");

    code.push_str(
        "pub fn get_component_from_content_type(content_type: &str) -> Option<String> {\n",
    );
    code.push_str("    match content_type {\n");

    // Generate reverse mappings, avoiding duplicates by using the first component
    // found for each content_type
    let mut content_type_to_component: HashMap<String, String> = HashMap::new();
    for (component_name, content_type) in &component_to_content_type {
        // Only keep the first component for each content_type to avoid duplicates
        content_type_to_component
            .entry(content_type.clone())
            .or_insert(component_name.clone());
    }

    for (content_type, component_name) in &content_type_to_component {
        code.push_str(&format!(
            "        \"{}\" => Some(\"{}\".to_string()),\n",
            content_type, component_name
        ));
    }

    code.push_str("        _ => None,\n");
    code.push_str("    }\n");
    code.push_str("}\n\n");

    // 3. Write generated file
    let output_path = Path::new(out_dir).join("content_kinds_generated.rs");
    fs::write(&output_path, code).map_err(|e| format!("Failed to write generated file: {}", e))?;

    println!("cargo:rerun-if-changed={}", config_path.display());

    Ok(())
}

/// Extract actual component mappings from routes configuration
fn extract_component_mappings_from_routes(
    content_root: &str,
    content_kinds: &[ContentKindConfig],
) -> HashMap<String, String> {
    let mut component_to_content_type: HashMap<String, String> = HashMap::new();

    // Load routes configuration
    match load_routes_config(content_root) {
        Ok(routes_config) => {
            for route in &routes_config.routes {
                if !route.get_enabled() {
                    continue;
                }

                // Option 1: Explicit content_type in route
                if let Some(content_type) = &route.content_type {
                    if content_kinds.iter().any(|kind| kind.name == *content_type) {
                        component_to_content_type
                            .insert(route.component.clone(), content_type.clone());
                        continue;
                    }
                }

                // Option 2: Infer from route path patterns
                for kind in content_kinds {
                    if route.path.contains(&format!("/{}", kind.name))
                        || route.path.contains(&format!("/{}", kind.directory))
                    {
                        if let Some(component) = route.get_metadata("component") {
                            component_to_content_type.insert(component, kind.name.clone());
                        }
                        break;
                    }
                }
            }
        }
        Err(e) => {
            eprintln!("Warning: Could not load routes config: {}", e);
        }
    }

    component_to_content_type
}

// This function is no longer needed - removed as part of unified content system
#[allow(dead_code)]
fn generate_content_struct(code: &mut String, kind: &ContentKindConfig) -> Result<(), String> {
    let struct_name = format!("{}Content", capitalize(&kind.name));

    code.push_str("#[derive(Debug, Clone, Serialize, Deserialize)]\n");
    code.push_str(&format!("pub struct {} {{\n", struct_name));
    code.push_str("    pub id: String,\n");
    code.push_str("    pub title: String,\n");
    code.push_str("    pub slug: String,\n");
    code.push_str("    pub language: String,\n");
    code.push_str("    pub categories: Vec<String>,\n");
    code.push_str("    pub tags: Vec<String>,\n");

    if kind.features.use_emojis {
        code.push_str("    pub emoji: Option<String>,\n");
    }

    if kind.features.use_feature {
        code.push_str("    pub featured: bool,\n");
    }

    // Add specialized fields
    if let Some(true) = kind.features.show_difficulty {
        code.push_str("    pub difficulty: Option<String>,\n");
    }
    if let Some(true) = kind.features.show_duration {
        code.push_str("    pub duration: Option<String>,\n");
    }
    if let Some(true) = kind.features.show_prerequisites {
        code.push_str("    pub prerequisites: Vec<String>,\n");
    }

    code.push_str("    pub content: String,\n");
    code.push_str("    pub created_at: String,\n");
    code.push_str("    pub updated_at: Option<String>,\n");
    code.push_str("}\n\n");

    // Generate ContentCardItem implementation
    code.push_str(&format!("impl ContentCardItem for {} {{\n", struct_name));
    code.push_str("    fn get_id(&self) -> &str { &self.id }\n");
    code.push_str("    fn get_title(&self) -> &str { &self.title }\n");
    code.push_str("    fn get_slug(&self) -> &str { &self.slug }\n");
    code.push_str("    fn get_categories(&self) -> &[String] { &self.categories }\n");
    code.push_str("    fn get_tags(&self) -> &[String] { &self.tags }\n");

    if kind.features.use_emojis {
        code.push_str("    fn get_emoji(&self) -> Option<&str> { self.emoji.as_deref() }\n");
    } else {
        code.push_str("    fn get_emoji(&self) -> Option<&str> { None }\n");
    }

    if kind.features.use_feature {
        code.push_str("    fn is_featured(&self) -> bool { self.featured }\n");
    } else {
        code.push_str("    fn is_featured(&self) -> bool { false }\n");
    }

    code.push_str("}\n\n");

    // Generate ContentItem implementation
    code.push_str(&format!("impl ContentItem for {} {{\n", struct_name));
    code.push_str("    fn render(&self, _config: &ContentConfig, _language: &str) -> AnyView {\n");
    code.push_str("        let title = self.title.clone();\n");
    code.push_str("        let content = self.content.clone();\n");

    if kind.features.use_emojis {
        code.push_str("        let emoji = self.emoji.clone();\n");
    }

    code.push_str("        view! {\n");
    code.push_str(&format!(
        "            <article class=\"{}\">\n",
        kind.features.style_css
    ));
    code.push_str("                <h1>{title}</h1>\n");

    if kind.features.use_emojis {
        code.push_str(
            "                {emoji.map(|e| view! { <span class=\"emoji\">{e}</span> })}\n",
        );
    }

    code.push_str("                <div class=\"content\" inner_html=content></div>\n");
    code.push_str("            </article>\n");
    code.push_str("        }.into_any()\n");
    code.push_str("    }\n\n");

    code.push_str("    fn validate(&self) -> Result<(), ValidationError> {\n");
    code.push_str("        if self.title.is_empty() {\n");
    code.push_str("            return Err(ValidationError {\n");
    code.push_str("                field: \"title\".to_string(),\n");
    code.push_str("                message: \"Title cannot be empty\".to_string(),\n");
    code.push_str("            });\n");
    code.push_str("        }\n");
    code.push_str("        if self.slug.is_empty() {\n");
    code.push_str("            return Err(ValidationError {\n");
    code.push_str("                field: \"slug\".to_string(),\n");
    code.push_str("                message: \"Slug cannot be empty\".to_string(),\n");
    code.push_str("            });\n");
    code.push_str("        }\n");
    code.push_str("        Ok(())\n");
    code.push_str("    }\n\n");

    code.push_str("    fn get_metadata(&self) -> ContentMetadata {\n");
    code.push_str("        ContentMetadata {\n");
    code.push_str("            id: self.id.clone(),\n");
    code.push_str("            title: self.title.clone(),\n");
    code.push_str("            slug: self.slug.clone(),\n");
    code.push_str("            language: self.language.clone(),\n");
    code.push_str(&format!(
        "            content_kind: \"{}\".to_string(),\n",
        kind.name
    ));
    code.push_str("            categories: self.categories.clone(),\n");
    code.push_str("            tags: self.tags.clone(),\n");

    if kind.features.use_emojis {
        code.push_str("            emoji: self.emoji.clone(),\n");
    } else {
        code.push_str("            emoji: None,\n");
    }

    if kind.features.use_feature {
        code.push_str("            featured: self.featured,\n");
    } else {
        code.push_str("            featured: false,\n");
    }

    code.push_str("            created_at: self.created_at.clone(),\n");
    code.push_str("            updated_at: self.updated_at.clone(),\n");
    code.push_str("        }\n");
    code.push_str("    }\n");
    code.push_str("}\n\n");

    Ok(())
}

fn capitalize(s: &str) -> String {
    let mut c = s.chars();
    match c.next() {
        None => String::new(),
        Some(f) => f.to_uppercase().collect::<String>() + c.as_str(),
    }
}
