//! SEO utilities module
//!
//! This module handles sitemap generation, robots.txt creation,
//! breadcrumb navigation, and other SEO-related functionality.

use std::collections::HashMap;

use rustelo_language::get_language_registry;

use super::components::RouteConfigToml;
use super::config::load_routes_config;
use super::language::{extract_lang_and_path, get_canonical_url};
// RouteMetadataAccess is only used by tools crate during build time

/// Generate sitemap entry data
#[derive(Debug, Clone, PartialEq)]
pub struct SitemapEntry {
    pub url: String,
    pub language: String,
    pub alternate_urls: Vec<AlternateUrl>,
    pub last_modified: Option<String>,
    pub priority: f32,
}

/// Alternate URL for sitemap
#[derive(Debug, Clone, PartialEq)]
pub struct AlternateUrl {
    pub language: String,
    pub url: String,
}

/// Generate sitemap data for all available routes
pub fn generate_sitemap_data(base_url: &str) -> Vec<SitemapEntry> {
    let config = load_routes_config();
    let language_registry = get_language_registry();
    let _available_languages = language_registry.get_available_languages();
    let mut entries = Vec::new();

    // Group routes by component to create alternate language entries
    let mut routes_by_component: HashMap<String, HashMap<String, &RouteConfigToml>> =
        HashMap::new();

    for route in &config.routes {
        if !route.get_enabled() || !route.get_show_in_sitemap() {
            continue;
        }

        let component = &route.component;
        if let Some(language) = route.get_language() {
            routes_by_component
                .entry(component.clone())
                .or_default()
                .insert(language, route);
        }
    }

    // Generate sitemap entries with alternates
    for (_, lang_routes) in routes_by_component {
        for (language, route) in &lang_routes {
            let url = if route.path == "/" {
                if language == language_registry.get_default_language() {
                    base_url.to_string()
                } else {
                    format!("{base_url}/{language}")
                }
            } else if language == language_registry.get_default_language()
                || route.path.starts_with(&format!("/{language}/"))
            {
                format!("{base_url}{}", route.path)
            } else {
                format!("{base_url}/{language}{}", route.path)
            };

            let mut alternate_urls = Vec::new();
            for (alt_lang, alt_route) in &lang_routes {
                let alt_url = if alt_route.path == "/" {
                    if alt_lang == language_registry.get_default_language() {
                        base_url.to_string()
                    } else {
                        format!("{base_url}/{alt_lang}")
                    }
                } else if alt_lang == language_registry.get_default_language()
                    || alt_route.path.starts_with(&format!("/{alt_lang}/"))
                {
                    format!("{base_url}{}", alt_route.path)
                } else {
                    format!("{base_url}/{alt_lang}{}", alt_route.path)
                };

                alternate_urls.push(AlternateUrl {
                    language: alt_lang.clone(),
                    url: alt_url,
                });
            }

            entries.push(SitemapEntry {
                url,
                language: language.clone(),
                alternate_urls,
                last_modified: None,
                priority: route.get_priority(),
            });
        }
    }

    entries
}

/// Generate robots.txt content
pub fn generate_robots_txt(base_url: &str) -> String {
    format!(
        "User-agent: *\nAllow: /\n\nSitemap: {}/sitemap.xml\n",
        base_url.trim_end_matches('/')
    )
}

/// Generate breadcrumb data for a given path
pub fn get_breadcrumbs(path: &str, base_url: &str) -> Vec<BreadcrumbItem> {
    let _language_registry = get_language_registry();
    let (language, clean_path) = extract_lang_and_path(path);
    let mut breadcrumbs = Vec::new();

    // Always add home
    let home_title = get_breadcrumb_title("home", &language);
    let home_url = get_canonical_url("/", &language, base_url);

    breadcrumbs.push(BreadcrumbItem {
        title: home_title,
        url: home_url,
        is_current: clean_path == "/",
    });

    // Add intermediate paths
    if clean_path != "/" {
        let parts: Vec<&str> = clean_path
            .trim_start_matches('/')
            .split('/')
            .filter(|p| !p.is_empty())
            .collect();
        let mut current_path = String::new();

        for (i, part) in parts.iter().enumerate() {
            current_path.push('/');
            current_path.push_str(part);

            let is_current = i == parts.len() - 1;
            let title = get_breadcrumb_title(part, &language);
            let url = get_canonical_url(&current_path, &language, base_url);

            breadcrumbs.push(BreadcrumbItem {
                title,
                url,
                is_current,
            });
        }
    }

    breadcrumbs
}

// Use BreadcrumbItem from utils module to avoid duplication
pub use super::utils::BreadcrumbItem;

/// Get breadcrumb title for a path segment (language-agnostic using i18n
/// system)
fn get_breadcrumb_title(segment: &str, _language: &str) -> String {
    // TODO: Translation system removed during routing crate extraction
    // This should be re-added through a trait-based abstraction
    // For now, use simple fallback: capitalize first letter of segment
    //
    // Use the i18n system to get proper translations for breadcrumb titles
    // let breadcrumb_key = format!("breadcrumb-{}", segment);
    // let translation = crate::i18n::t_for_language(language, &breadcrumb_key);

    // Fallback: capitalize first letter of segment
    let mut chars: Vec<char> = segment.chars().collect();
    if !chars.is_empty() {
        chars[0] = chars[0].to_uppercase().next().unwrap_or(chars[0]);
        chars.into_iter().collect()
    } else {
        segment.to_string()
    }
}

/// Handle a route and return metadata
pub fn handle_route_metadata(path: &str, base_url: &str) -> super::defs::RouteMetadata {
    use super::engine::resolve_route;

    let resolved = resolve_route(path);
    let _canonical_url = get_canonical_url(path, &resolved.language, base_url);

    super::defs::RouteMetadata::new(path, &resolved.language)
        .with_title(&format!("Page - {path}"))
        .with_description("Page description")
        .with_keywords(vec!["rust", "developer", "infrastructure"])
}

/// Get the language-specific home URL
pub fn get_home_url_for_language(language: &str) -> String {
    let language_registry = get_language_registry();
    let default_language = language_registry.get_default_language();

    if language == default_language {
        "/".to_string()
    } else {
        format!("/{language}")
    }
}

/// Get navigation data for a path
pub fn get_navigation_data(path: &str, base_url: &str) -> super::defs::NavigationData {
    use super::engine::resolve_route;

    let resolved = resolve_route(path);
    let breadcrumbs = get_breadcrumbs(path, base_url);

    super::defs::NavigationData {
        current_path: path.to_string(),
        language: resolved.language,
        breadcrumbs,
        is_not_found: resolved.component.is_none(),
    }
}

/// Generate XML sitemap content
pub fn generate_sitemap_xml(base_url: &str) -> String {
    let entries = generate_sitemap_data(base_url);
    let mut xml = String::from(
        r#"<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"
        xmlns:xhtml="http://www.w3.org/1999/xhtml">
"#,
    );

    for entry in &entries {
        xml.push_str(&format!(
            r#"    <url>
        <loc>{}</loc>
        <priority>{}</priority>
"#,
            entry.url, entry.priority
        ));

        if let Some(last_modified) = &entry.last_modified {
            xml.push_str(&format!("        <lastmod>{}</lastmod>\n", last_modified));
        }

        // Add alternate language links
        for alt_url in &entry.alternate_urls {
            xml.push_str(&format!(
                r#"        <xhtml:link rel="alternate" hreflang="{}" href="{}"/>
"#,
                alt_url.language, alt_url.url
            ));
        }

        xml.push_str("    </url>\n");
    }

    xml.push_str("</urlset>\n");
    xml
}

/// Generate meta tags for SEO
pub fn generate_meta_tags(path: &str, base_url: &str) -> String {
    let (language, _clean_path) = extract_lang_and_path(path);
    let config = load_routes_config();

    // Find route configuration for this path and language
    let route = config
        .routes
        .iter()
        .find(|r| r.get_enabled() && r.path == path && r.get_language() == Some(language.clone()));

    let mut meta_tags = String::new();

    if let Some(route) = route {
        // Title
        // TODO: Translation system removed during routing crate extraction
        // For now, use the key directly (should be human-readable)
        if let Some(title_key) = route.get_title_key() {
            // let title = crate::i18n::t_for_language(&language, &title_key);
            let title = title_key; // Use key directly for now
            meta_tags.push_str(&format!(r#"<title>{}</title>"#, title));
            meta_tags.push_str(&format!(
                r#"<meta property="og:title" content="{}">"#,
                title
            ));
        }

        // Description
        // TODO: Translation system removed during routing crate extraction
        // For now, use the key directly (should be human-readable)
        if let Some(description_key) = route.get_description_key() {
            // let description = crate::i18n::t_for_language(&language, &description_key);
            let description = description_key; // Use key directly for now
            meta_tags.push_str(&format!(
                r#"<meta name="description" content="{}">"#,
                description
            ));
            meta_tags.push_str(&format!(
                r#"<meta property="og:description" content="{}">"#,
                description
            ));
        }

        // Keywords
        if let Some(keywords) = route.get_keywords() {
            meta_tags.push_str(&format!(r#"<meta name="keywords" content="{}">"#, keywords));
        }

        // Canonical URL
        let canonical_url = get_canonical_url(path, &language, base_url);
        meta_tags.push_str(&format!(
            r#"<link rel="canonical" href="{}">"#,
            canonical_url
        ));
        meta_tags.push_str(&format!(
            r#"<meta property="og:url" content="{}">"#,
            canonical_url
        ));

        // Language
        meta_tags.push_str(&format!(r#"<html lang="{}">"#, language));

        // Alternate language links
        let language_registry = get_language_registry();
        let available_languages = language_registry.get_available_languages();

        for lang in &available_languages {
            if let Some(alt_route) = config.routes.iter().find(|r| {
                r.get_enabled()
                    && r.component == route.component
                    && r.get_language() == Some(lang.clone())
            }) {
                let alt_url = get_canonical_url(&alt_route.path, lang, base_url);
                meta_tags.push_str(&format!(
                    r#"<link rel="alternate" hreflang="{}" href="{}">"#,
                    lang, alt_url
                ));
            }
        }
    }

    // Common meta tags
    meta_tags.push_str(r#"<meta charset="UTF-8">"#);
    meta_tags.push_str(r#"<meta name="viewport" content="width=device-width, initial-scale=1.0">"#);
    meta_tags.push_str(r#"<meta property="og:type" content="website">"#);

    meta_tags
}

/// Calculate SEO score for a route
pub fn calculate_seo_score(path: &str) -> f32 {
    let (language, _clean_path) = extract_lang_and_path(path);
    let config = load_routes_config();

    let route = config
        .routes
        .iter()
        .find(|r| r.get_enabled() && r.path == path && r.get_language() == Some(language.clone()));

    if let Some(route) = route {
        let mut score = 0.0f32;

        // Title exists
        if route.get_title_key().is_some() {
            score += 25.0;
        }

        // Description exists
        if route.get_description_key().is_some() {
            score += 25.0;
        }

        // Keywords exist
        if route.get_keywords().is_some() {
            score += 15.0;
        }

        // Shows in sitemap
        if route.get_show_in_sitemap() {
            score += 20.0;
        }

        // Has canonical path
        if route.get_canonical_path().is_some() {
            score += 15.0;
        }

        score
    } else {
        0.0
    }
}

/// Get all SEO issues for routes
pub fn get_seo_issues() -> Vec<SeoIssue> {
    let config = load_routes_config();
    let mut issues = Vec::new();

    for route in &config.routes {
        if !route.get_enabled() {
            continue;
        }

        let mut route_issues = Vec::new();

        // Check for missing title
        if route.get_title_key().is_none() {
            route_issues.push("Missing title_key".to_string());
        }

        // Check for missing description
        if route.get_description_key().is_none() {
            route_issues.push("Missing description_key".to_string());
        }

        // Check for missing keywords
        if route.get_keywords().is_none() {
            route_issues.push("Missing keywords".to_string());
        }

        // Check priority
        let priority = route.get_priority();
        if priority <= 0.0 || priority > 1.0 {
            route_issues.push(format!("Invalid priority: {}", priority));
        }

        if !route_issues.is_empty() {
            issues.push(SeoIssue {
                path: route.path.clone(),
                language: route.get_language().unwrap_or_default(),
                issues: route_issues,
                score: calculate_seo_score(&route.path),
            });
        }
    }

    issues
}

/// SEO issue representation
#[derive(Debug, Clone)]
pub struct SeoIssue {
    pub path: String,
    pub language: String,
    pub issues: Vec<String>,
    pub score: f32,
}

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

    #[test]
    fn test_generate_robots_txt() {
        let robots = generate_robots_txt("https://example.com");
        assert!(robots.contains("User-agent: *"));
        assert!(robots.contains("Allow: /"));
        assert!(robots.contains("Sitemap: https://example.com/sitemap.xml"));
    }

    #[test]
    fn test_get_home_url_for_language() {
        let language_registry = get_language_registry();
        let default_language = language_registry.get_default_language();

        let home_url = get_home_url_for_language(default_language);
        assert_eq!(home_url, "/");

        let alt_home_url = get_home_url_for_language("es");
        if "es" != default_language {
            assert_eq!(alt_home_url, "/es");
        }
    }

    #[test]
    fn test_generate_sitemap_data() {
        let sitemap_data = generate_sitemap_data("https://example.com");

        // Should have at least some entries if routes are configured
        println!("Sitemap entries count: {}", sitemap_data.len());

        for entry in sitemap_data.iter().take(3) {
            println!("Entry: {} ({})", entry.url, entry.language);
            assert!(entry.priority >= 0.0 && entry.priority <= 1.0);
            assert!(entry.url.starts_with("https://example.com"));
        }
    }

    #[test]
    fn test_breadcrumb_generation() {
        let breadcrumbs = get_breadcrumbs("/blog/tech/article", "https://example.com");

        // Should have at least home
        assert!(!breadcrumbs.is_empty());
        assert_eq!(
            breadcrumbs[0].title,
            get_breadcrumb_title("home", &extract_lang_and_path("/blog/tech/article").0)
        );

        println!("Breadcrumbs: {:?}", breadcrumbs);
    }

    #[test]
    fn test_seo_score_calculation() {
        let score = calculate_seo_score("/");
        assert!((0.0..=100.0).contains(&score));
        println!("SEO score for /: {}", score);
    }

    #[test]
    fn test_generate_sitemap_xml() {
        let xml = generate_sitemap_xml("https://example.com");
        assert!(xml.contains("<?xml version=\"1.0\""));
        assert!(xml.contains("<urlset"));
        assert!(xml.contains("</urlset>"));
        println!("Generated sitemap XML length: {}", xml.len());
    }
}
