use super::CrawlerError;
use log::{info, warn};
use reqwest::Client;
use sitemap::reader::{SiteMapEntity, SiteMapReader};
use std::collections::HashSet;
use std::io::Cursor;
use url::Url;

/// Fetch and parse sitemap.xml from a domain
pub async fn fetch_sitemap_urls(
    client: &Client,
    base_url: &Url,
) -> Result<HashSet<Url>, CrawlerError> {
    let mut all_urls = HashSet::new();

    // Try common sitemap locations
    let sitemap_urls = vec![
        format!(
            "{}://{}/sitemap.xml",
            base_url.scheme(),
            base_url.host_str().unwrap_or("")
        ),
        format!(
            "{}://{}/sitemap_index.xml",
            base_url.scheme(),
            base_url.host_str().unwrap_or("")
        ),
        format!(
            "{}://{}/sitemap/sitemap.xml",
            base_url.scheme(),
            base_url.host_str().unwrap_or("")
        ),
    ];

    for sitemap_url in sitemap_urls {
        match fetch_and_parse_sitemap(client, &sitemap_url).await {
            Ok(urls) => {
                if !urls.is_empty() {
                    info!("📍 Found {} URLs in sitemap: {}", urls.len(), sitemap_url);
                    all_urls.extend(urls);
                }
            }
            Err(e) => {
                warn!("⚠️  Could not fetch sitemap {}: {}", sitemap_url, e);
            }
        }
    }

    Ok(all_urls)
}

/// Fetch and parse a single sitemap (handles both sitemap index and URL sets)
#[async_recursion::async_recursion]
async fn fetch_and_parse_sitemap(
    client: &Client,
    sitemap_url: &str,
) -> Result<HashSet<Url>, CrawlerError> {
    let response = client.get(sitemap_url).send().await?.error_for_status()?;

    let content = response.bytes().await?;
    let cursor = Cursor::new(content);

    let parser = SiteMapReader::new(cursor);
    let mut urls = HashSet::new();

    for entity in parser {
        match entity {
            SiteMapEntity::Url(url_entry) => {
                if let Some(url) = url_entry.loc.get_url()
                    && let Ok(parsed_url) = Url::parse(url.as_str())
                {
                    urls.insert(parsed_url);
                }
            }
            SiteMapEntity::SiteMap(sitemap_entry) => {
                // Recursive: fetch nested sitemap
                if let Some(nested_url) = sitemap_entry.loc.get_url() {
                    match fetch_and_parse_sitemap(client, nested_url.as_str()).await {
                        Ok(nested_urls) => {
                            info!("  📍 Found {} URLs in nested sitemap", nested_urls.len());
                            urls.extend(nested_urls);
                        }
                        Err(e) => {
                            warn!("  ⚠️  Could not fetch nested sitemap {}: {}", nested_url, e);
                        }
                    }
                }
            }
            SiteMapEntity::Err(e) => {
                warn!("  ⚠️  Error parsing sitemap entry: {}", e);
            }
        }
    }

    Ok(urls)
}
