use std::collections::HashMap;

use crate::{
    models::{mastodon::MastodonEntry, Domain, List, Search},
    sources::manager::SourceManagerHandle,
};

const MASTODON_CSV_HEADER: &str =
    "domain,severity,public_comment,reject_media,reject_reports,obfuscate";

pub async fn fetch_all(handles: Vec<SourceManagerHandle>) -> anyhow::Result<List> {
    let mut list = List::empty();
    for handle in handles {
        match handle.fetch().await {
            Ok(ls) => list.merge(ls),
            Err(err) => {
                tracing::error!("failed to fetch list -- {err}");
            }
        }
    }

    Ok(list)
}

pub async fn fetch_all_as_mastodon_csv(
    handles: Vec<SourceManagerHandle>,
) -> anyhow::Result<String> {
    let list = fetch_all(handles).await?;

    let entries: Vec<MastodonEntry> = list.domains.into_iter().map(Domain::into).collect();

    let mut csv = String::from(MASTODON_CSV_HEADER);
    for entry in entries {
        let line = format!("\n{}", entry.as_csv_entry());
        csv.push_str(&line);
    }

    Ok(csv)
}

pub async fn search_domain(
    query: Search,
    handles: Vec<SourceManagerHandle>,
) -> anyhow::Result<List> {
    let list = fetch_all(handles).await?;

    let mut count: HashMap<String, usize> = HashMap::new();
    let domains: Vec<Domain> = list
        .domains
        .into_iter()
        .filter(|d| {
            if let Some(domain_filter) = &query.domain {
                d.domain.contains(domain_filter)
            } else {
                true
            }
        })
        .filter(|d| {
            if let Some(threshold_filter) = query.threshold {
                let k = d.key();
                let n = count.get(&k).copied().unwrap_or(0);
                count.insert(k, n + 1);

                n + 1 >= threshold_filter
            } else {
                true
            }
        })
        .collect();

    Ok(domains.into())
}
