//! Client Route Analysis
//!
//! This module enhances the existing client route documentation by analyzing
//! TOML configuration files and generating comprehensive documentation.

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

use toml::Value;

use crate::route_analysis::{PageRouteInfo, RouteDocumentation, RouteParameter};
use crate::utils::RouteMetadataAccess;

/// Generate comprehensive client route documentation
pub fn generate_client_route_documentation(
    content_root: &str,
    config_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut documentation = RouteDocumentation::new();

    // Load routes from TOML configuration files
    let routes_dir = Path::new(content_root).join("config/routes");

    if routes_dir.exists() {
        let page_routes = load_all_route_configs(&routes_dir)?;
        documentation.page_routes.extend(page_routes);
    }

    // Save documentation files
    documentation.save_to_toml(config_path)?;
    documentation.generate_markdown(config_path)?;

    Ok(())
}

/// Load all route configuration files from the routes directory
pub fn load_all_route_configs(
    routes_dir: &Path,
) -> Result<Vec<PageRouteInfo>, Box<dyn std::error::Error>> {
    let mut all_routes = Vec::new();

    // Read all TOML files in the routes directory
    for entry in std::fs::read_dir(routes_dir)? {
        let entry = entry?;
        let path = entry.path();

        if path.is_file() && path.extension().is_some_and(|ext| ext == "toml") {
            let routes = load_route_config_file(&path)?;
            all_routes.extend(routes);
        }
    }

    Ok(all_routes)
}

/// Load route configuration from a single TOML file
fn load_route_config_file(
    file_path: &Path,
) -> Result<Vec<PageRouteInfo>, Box<dyn std::error::Error>> {
    let content = fs::read_to_string(file_path)?;
    let parsed: Value = toml::from_str(&content)?;

    let mut routes = Vec::new();

    if let Some(routes_array) = parsed.get("routes").and_then(|v| v.as_array()) {
        for route_value in routes_array {
            if let Ok(route_info) = parse_route_info(route_value, file_path) {
                routes.push(route_info);
            }
        }
    }

    Ok(routes)
}

/// Parse a route info from TOML value
fn parse_route_info(
    route_value: &Value,
    file_path: &Path,
) -> Result<PageRouteInfo, Box<dyn std::error::Error>> {
    let path = route_value
        .get("path")
        .and_then(|v| v.as_str())
        .ok_or("Missing path field")?
        .to_string();

    let component = route_value
        .get("component")
        .and_then(|v| v.as_str())
        .unwrap_or("Unknown")
        .to_string();

    let page_component = route_value
        .get("page_component")
        .and_then(|v| v.as_str())
        .unwrap_or(&format!("{}Page", component))
        .to_string();

    let unified_component = route_value
        .get("unified_component")
        .and_then(|v| v.as_str())
        .unwrap_or(&format!("Unified{}Page", component))
        .to_string();

    let module_path = route_value
        .get("module_path")
        .and_then(|v| v.as_str())
        .map(|s| s.to_string());

    let language = route_value
        .get("language")
        .and_then(|v| v.as_str())
        .unwrap_or("en")
        .to_string();

    let enabled = route_value
        .get("enabled")
        .and_then(|v| v.as_bool())
        .unwrap_or(true);

    let priority = route_value
        .get("priority")
        .and_then(|v| v.as_float())
        .unwrap_or(0.5);

    let requires_auth = route_value.get("requires_auth").and_then(|v| v.as_bool());

    let menu_group = route_value
        .get("menu_group")
        .and_then(|v| v.as_str())
        .map(|s| s.to_string());

    let menu_order = route_value
        .get("menu_order")
        .and_then(|v| v.as_integer())
        .map(|i| i as i32);

    let menu_icon = route_value
        .get("menu_icon")
        .and_then(|v| v.as_str())
        .map(|s| s.to_string());

    let title_key = route_value
        .get("title_key")
        .and_then(|v| v.as_str())
        .unwrap_or(&format!("{}-title", component.to_lowercase()))
        .to_string();

    let description_key = route_value
        .get("description_key")
        .and_then(|v| v.as_str())
        .map(|s| s.to_string());

    let keywords: Vec<String> = route_value
        .get("keywords")
        .and_then(|v| v.as_array())
        .map(|arr| {
            arr.iter()
                .filter_map(|v| v.as_str())
                .map(|s| s.to_string())
                .collect()
        })
        .unwrap_or_default();

    let i18n_patterns = route_value
        .get("i18n_patterns")
        .and_then(|v| v.as_array())
        .map(|arr| {
            arr.iter()
                .filter_map(|v| v.as_str())
                .map(|s| s.to_string())
                .collect()
        })
        .unwrap_or_default();

    // Extract route parameters from path
    let parameters = crate::route_analysis::extract_path_parameters(&path);

    // Convert props to HashMap
    let props = if let Some(props_value) = route_value.get("props") {
        extract_props_map(props_value)
    } else {
        HashMap::new()
    };

    // Create source reference for TOML file
    let src_ref = Some(crate::route_analysis::SourceReference {
        path: crate::route_analysis::make_relative_path(file_path),
        line: 1, // TOML parsing doesn't easily provide line numbers, use 1 as default
        context: "page route definition".to_string(),
    });

    // Create metadata HashMap
    let mut metadata = HashMap::new();
    metadata.insert("enabled".to_string(), toml::Value::Boolean(enabled));
    metadata.insert("priority".to_string(), toml::Value::Float(priority));
    metadata.insert(
        "title_key".to_string(),
        toml::Value::String(title_key.clone()),
    );
    metadata.insert(
        "language".to_string(),
        toml::Value::String(language.clone()),
    );
    metadata.insert(
        "unified_component".to_string(),
        toml::Value::String(unified_component.clone()),
    );

    if let Some(req_auth) = requires_auth {
        metadata.insert("requires_auth".to_string(), toml::Value::Boolean(req_auth));
    }
    if let Some(menu_grp) = menu_group.clone() {
        metadata.insert("menu_group".to_string(), toml::Value::String(menu_grp));
    }
    if let Some(menu_ord) = menu_order {
        metadata.insert(
            "menu_order".to_string(),
            toml::Value::Integer(menu_ord as i64),
        );
    }
    if let Some(menu_icn) = menu_icon.clone() {
        metadata.insert("menu_icon".to_string(), toml::Value::String(menu_icn));
    }
    if let Some(desc_key) = description_key.clone() {
        metadata.insert("description_key".to_string(), toml::Value::String(desc_key));
    }
    if !keywords.is_empty() {
        metadata.insert(
            "keywords".to_string(),
            toml::Value::Array(
                keywords
                    .iter()
                    .map(|k| toml::Value::String(k.clone()))
                    .collect(),
            ),
        );
    }

    Ok(PageRouteInfo {
        path,
        component,
        page_component,
        unified_component,
        module_path,
        language,
        enabled,
        priority,
        requires_auth,
        menu_group,
        menu_order,
        menu_icon,
        title_key,
        description_key,
        keywords,
        i18n_patterns,
        parameters,
        props,
        src_ref,
    })
}

/// Extract props map from TOML value
fn extract_props_map(props_value: &Value) -> HashMap<String, Value> {
    let mut props_map = HashMap::new();

    if let Some(table) = props_value.as_table() {
        for (key, value) in table {
            props_map.insert(key.clone(), value.clone());
        }
    }

    props_map
}

/// Enhanced route parameter extraction with type inference
pub fn extract_enhanced_route_parameters(path: &str, route_config: &Value) -> Vec<RouteParameter> {
    let mut parameters = crate::route_analysis::extract_path_parameters(path);

    // Try to enhance parameters with type information from config
    if let Some(param_extraction) = route_config.get("parameter_extraction") {
        for param in &mut parameters {
            if let Some(param_config) = param_extraction.get(&param.name) {
                if let Some(param_type) = param_config.as_str() {
                    param.param_type = infer_rust_type_from_extraction(param_type);
                }
            }
        }
    }

    // Add special route flags as parameters
    if route_config
        .get("slug_param")
        .and_then(|v| v.as_bool())
        .unwrap_or(false)
    {
        parameters.push(RouteParameter {
            name: "slug".to_string(),
            param_type: "String".to_string(),
            source: "path".to_string(),
            optional: false,
            description: Some("Content slug identifier".to_string()),
        });
    }

    if route_config
        .get("category_param")
        .and_then(|v| v.as_bool())
        .unwrap_or(false)
    {
        parameters.push(RouteParameter {
            name: "category".to_string(),
            param_type: "String".to_string(),
            source: "path".to_string(),
            optional: false,
            description: Some("Content category filter".to_string()),
        });
    }

    if route_config
        .get("content_type_param")
        .and_then(|v| v.as_bool())
        .unwrap_or(false)
    {
        if let Some(content_type) = route_config
            .get("props")
            .and_then(|p| p.get("content_type"))
            .and_then(|ct| ct.as_str())
        {
            parameters.push(RouteParameter {
                name: "content_type".to_string(),
                param_type: "String".to_string(),
                source: "config".to_string(),
                optional: false,
                description: Some(format!("Fixed content type: {}", content_type)),
            });
        }
    }

    parameters
}

/// Infer Rust type from parameter extraction method
fn infer_rust_type_from_extraction(extraction_method: &str) -> String {
    match extraction_method {
        "from_path" => "String".to_string(),
        "from_parameters" => "String".to_string(),
        "from_query" => "Option<String>".to_string(),
        "from_body" => "serde_json::Value".to_string(),
        _ => "String".to_string(),
    }
}

/// Generate route documentation with enhanced analysis
pub fn generate_enhanced_client_documentation(
    content_root: &str,
    config_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut documentation = RouteDocumentation::new();

    // Load enhanced route information
    let routes_dir = Path::new(content_root).join("config/routes");

    if routes_dir.exists() {
        for entry in std::fs::read_dir(&routes_dir)? {
            let entry = entry?;
            let path = entry.path();

            if path.is_file() && path.extension().is_some_and(|ext| ext == "toml") {
                let content = fs::read_to_string(&path)?;
                let parsed: Value = toml::from_str(&content)?;

                if let Some(routes_array) = parsed.get("routes").and_then(|v| v.as_array()) {
                    for route_value in routes_array {
                        if let Ok(mut route_info) = parse_route_info(route_value, &path) {
                            // Enhance with additional parameter analysis
                            route_info.parameters =
                                extract_enhanced_route_parameters(&route_info.path, route_value);
                            documentation.page_routes.push(route_info);
                        }
                    }
                }
            }
        }
    }

    // Generate separate language-specific documentation
    generate_language_specific_docs(&documentation, config_path)?;

    // Save complete documentation
    documentation.save_to_toml(config_path)?;
    documentation.generate_markdown(config_path)?;

    Ok(())
}

/// Generate language-specific documentation files
fn generate_language_specific_docs(
    documentation: &RouteDocumentation,
    config_path: &str,
) -> Result<(), Box<dyn std::error::Error>> {
    // Group routes by language
    let mut routes_by_lang: HashMap<String, Vec<&PageRouteInfo>> = HashMap::new();

    for route in &documentation.page_routes {
        routes_by_lang
            .entry(route.language.clone())
            .or_default()
            .push(route);
    }

    // Generate separate TOML files for each language
    let config_dir = Path::new(config_path);
    for (lang, routes) in routes_by_lang {
        let lang_file = config_dir.join(format!("client_routes_{}.toml", lang));
        let lang_content = toml::to_string_pretty(&routes)?;
        fs::write(&lang_file, lang_content)?;
    }

    Ok(())
}
