use serde_json::{Map, Value};
use tokio::time::{sleep, Duration};

use super::config::{RegistryEngine, VatIdSearchEngine};
use crate::audit::AuditBus;
use crate::scrape::bizzy::enrich_nl_companies_vat_from_bizzy;
use crate::scrape::kvk::fetch_all_kvk_companies;
use crate::scrape::egrul::fetch_egrul_rows;
use crate::scrape::mapping::{
    map_egrul_api_row_to_global, map_kvk_company_to_global, map_northdata_hit_to_global,
    map_registries_io_company_to_global, map_registries_io_pl_detail_to_global,
};
use crate::scrape::northdata::fetch_northdata_suggest;
use crate::scrape::registries_io::{
    fetch_all_registries_io_companies, fetch_registries_io_company_detail,
};

/// Fetch + map to `global_companies_registry` rows.
pub async fn fetch_mapped_global_rows(
    http: &reqwest::Client,
    engine: RegistryEngine,
    query: &str,
    country_code: &str,
    kvk_api_url: &str,
    northdata_base_url: &str,
    egrul_base_url: &str,
    registries_io_base_url: &str,
    registries_io_page_limit: u32,
    northdata_cookie: Option<&str>,
    vat: VatIdSearchEngine,
    audit: Option<AuditBus>,
    http_audit_profile: Option<String>,
) -> Vec<Map<String, Value>> {
    let cc = country_code.to_uppercase();
    match engine {
        RegistryEngine::Kvk => {
            let mut companies = fetch_all_kvk_companies(
                http,
                kvk_api_url,
                query,
                audit.clone(),
                http_audit_profile.clone(),
            )
            .await;
            if matches!(vat, VatIdSearchEngine::Bizzy) {
                enrich_nl_companies_vat_from_bizzy(
                    http,
                    &mut companies,
                    audit.clone(),
                    http_audit_profile.clone(),
                )
                .await;
            }
            companies
                .into_iter()
                .filter_map(|c| map_kvk_company_to_global(&c, &cc))
                .collect()
        }
        RegistryEngine::Northdata => {
            let meta_prof = http_audit_profile.clone();
            let raw = fetch_northdata_suggest(
                http,
                northdata_base_url,
                query,
                &cc,
                northdata_cookie,
                audit.as_ref(),
                meta_prof,
            )
            .await;
            raw.iter()
                .filter_map(|m| map_northdata_hit_to_global(m, &cc))
                .collect()
        }
        RegistryEngine::Egrul => {
            let raw = fetch_egrul_rows(
                http,
                egrul_base_url,
                query,
                audit.as_ref(),
                http_audit_profile,
            )
            .await;
            raw.iter()
                .filter_map(|m| map_egrul_api_row_to_global(m))
                .collect()
        }
        RegistryEngine::RegistriesIo => {
            let base = registries_io_base_url.trim_end_matches('/');
            let raw = fetch_all_registries_io_companies(
                http,
                base,
                query,
                country_code,
                registries_io_page_limit.max(1),
                audit.as_ref(),
                http_audit_profile.clone(),
            )
            .await;
            let cc_lower = country_code.trim().to_lowercase();
            let mut out: Vec<Map<String, Value>> = Vec::new();
            const DETAIL_PAUSE_MS: u64 = 250;
            for c in &raw {
                let mut row: Option<Map<String, Value>> = None;
                if cc == "PL" {
                    if let Some(slug) = c.slug.as_deref().map(str::trim).filter(|s| !s.is_empty()) {
                        sleep(Duration::from_millis(DETAIL_PAUSE_MS)).await;
                        if let Some(detail_val) = fetch_registries_io_company_detail(
                            http,
                            base,
                            slug,
                            &cc_lower,
                            audit.as_ref(),
                            http_audit_profile.clone(),
                        )
                        .await
                        {
                            if let Some(obj) = detail_val.as_object() {
                                row = map_registries_io_pl_detail_to_global(obj, &cc, base);
                            }
                        }
                    }
                }
                if row.is_none() {
                    row = map_registries_io_company_to_global(c, &cc, base);
                }
                if let Some(m) = row {
                    out.push(m);
                }
            }
            out
        }
    }
}
