//! CLI port of `scripts/scrape_global_registry.py` — KVK / Northdata → Athena
//! `global_companies_registry` (+ `ee_companies` when EE).

use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;

use clap::{Parser, ValueEnum};
use dexter_sentinel::scrape::global::{
    run_randomized_registry_loop, run_single_registry_pass, GlobalRegistryPipelineConfig,
    RegistryEngine, VatIdSearchEngine,
};
use dexter_sentinel::scrape::DexterAthena;

#[derive(Debug, Clone, ValueEnum)]
enum SearchEngine {
    Kvk,
    Northdata,
}

#[derive(Debug, Clone, ValueEnum)]
enum VatCli {
    None,
    Bizzy,
}

#[derive(Parser, Debug)]
#[command(
    name = "dexter-scrape",
    about = "Global company registry scraper (KVK/Northdata) with optional Athena upload"
)]
#[command(group(
    clap::ArgGroup::new("query_mode")
        .required(true)
        .args(["query", "randomize_query"])
))]
struct Cli {
    /// Two-letter ISO country code (e.g., NL, EE)
    #[arg(short = 'c', long)]
    country_code: String,

    /// Target search engine to scrape from
    #[arg(short = 's', long)]
    search_engine: SearchEngine,

    /// Specific company name or fragment to search for
    #[arg(short = 'q', long)]
    query: Option<String>,

    /// Path to output the raw scraped rows (CSV format)
    #[arg(short = 'o', long, default_value = "global_registry_scrape.csv")]
    output: PathBuf,

    /// URL for the Dexter Athena Gateway
    #[arg(long, default_value = "https://cluster.athena-db.com")]
    athena_url: String,

    /// API key for the Dexter Athena Gateway (also uses ATHENA_API_KEY env)
    #[arg(long, env = "ATHENA_API_KEY")]
    athena_key: Option<String>,

    /// Value of the X-Athena-Client header
    #[arg(long, default_value = "dexter")]
    athena_client: String,

    /// Optional X-User-Id header for the Athena Gateway inserts
    #[arg(long, env = "ATHENA_USER_ID")]
    athena_user_id: Option<String>,

    /// Optional X-Company-Id header for the Athena Gateway inserts
    #[arg(long, env = "ATHENA_COMPANY_ID")]
    athena_company_id: Option<String>,

    /// Optional X-Organization-Id header for the Athena Gateway inserts
    #[arg(long, env = "ATHENA_ORGANIZATION_ID")]
    athena_organization_id: Option<String>,

    /// Print function timing and memory telemetry output (if instrumented)
    #[arg(long, default_value_t = false)]
    telemetry: bool,

    /// Enable recursive continuous scraping by using the incoming dataset to generate random queries
    #[arg(short = 'r', long, default_value_t = false)]
    randomize_query: bool,

    /// Minimum string length when randomly slicing company names for the next query
    #[arg(long, default_value_t = 3)]
    min_query_length: usize,

    /// Maximum string length when randomly slicing company names for the next query
    #[arg(long, default_value_t = 8)]
    max_query_length: usize,

    /// Path to file containing English/Dutch words to use as fallback random queries
    #[arg(long)]
    randomize_words_file: Option<PathBuf>,

    /// Initial CSV file to seed the randomize query algorithm with names
    #[arg(long)]
    randomize_seed_csv: Option<PathBuf>,

    /// Prevent loading the global_registry_scrape CSV as the query suggestion seed
    #[arg(long, default_value_t = false)]
    randomize_no_seed_csv: bool,

    /// Endpoint for the KVK search API
    #[arg(long, default_value = "https://web-api.kvk.nl/zoeken/v3/search")]
    kvk_api_url: String,

    /// URL prefix to use when querying Northdata
    #[arg(long, default_value = "https://www.northdata.com")]
    northdata_base_url: String,

    /// Path to a file holding NORTHDATA_COOKIE (used when scraping Northdata)
    #[arg(long)]
    northdata_cookie_file: Option<PathBuf>,

    /// Do not overwrite output CSV across iterations (append rows instead)
    #[arg(short = 'a', long, default_value_t = false)]
    append_csv: bool,

    /// Max concurrent network inserts targeting Athena
    #[arg(long, default_value_t = 25)]
    max_workers: usize,

    /// Dry run: scrape and save locally but do not upload to Athena
    #[arg(long, default_value_t = false)]
    no_insert: bool,

    /// Try to enrich missing VAT identifiers by querying Bizzy (NL only)
    #[arg(long, value_enum, default_value_t = VatCli::None)]
    vat_id_search_engine: VatCli,
}

#[tokio::main]
async fn main() -> anyhow::Result<()> {
    dotenv::dotenv().ok();
    tracing_subscriber::fmt()
        .with_env_filter(
            tracing_subscriber::EnvFilter::try_from_default_env()
                .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
        )
        .init();

    let cli = Cli::parse();

    let cc = cli.country_code.trim().to_uppercase();
    if cc.len() != 2 || !cc.chars().all(|c| c.is_ascii_alphabetic()) {
        anyhow::bail!("--country-code must be ISO 3166-1 alpha-2 (e.g. NL)");
    }

    let engine = match cli.search_engine {
        SearchEngine::Kvk => RegistryEngine::Kvk,
        SearchEngine::Northdata => RegistryEngine::Northdata,
    };

    if matches!(engine, RegistryEngine::Kvk) && cc != "NL" {
        anyhow::bail!("--search-engine kvk requires --country-code NL");
    }

    let vat = match cli.vat_id_search_engine {
        VatCli::None => VatIdSearchEngine::None,
        VatCli::Bizzy => VatIdSearchEngine::Bizzy,
    };
    if matches!(vat, VatIdSearchEngine::Bizzy) {
        if cc != "NL" {
            anyhow::bail!("--vat-id-search-engine bizzy requires --country-code NL");
        }
        if !matches!(engine, RegistryEngine::Kvk) {
            anyhow::bail!("--vat-id-search-engine bizzy requires --search-engine kvk");
        }
    }

    let insert = !cli.no_insert;
    let dexter = if insert {
        let athena_key = cli
            .athena_key
            .filter(|s| !s.is_empty())
            .or_else(|| std::env::var("ATHENA_API_KEY").ok())
            .filter(|s| !s.is_empty())
            .ok_or_else(|| {
                anyhow::anyhow!("set --athena-key or ATHENA_API_KEY when not using --no-insert")
            })?;
        Some(Arc::new(
            DexterAthena::from_cli(
                &cli.athena_url,
                &athena_key,
                &cli.athena_client,
                cli.athena_user_id.clone(),
                cli.athena_company_id.clone(),
                cli.athena_organization_id.clone(),
                None,
            )
            .await?,
        ))
    } else {
        None
    };

    if cli.telemetry {
        dexter_sentinel::scrape::log::TELEMETRY.store(true, std::sync::atomic::Ordering::Relaxed);
        dexter_sentinel::scrape::log::rate_reset();
        tokio::spawn(async {
            dexter_sentinel::scrape::log::rate_logger_loop_global().await;
        });
    }

    let http = reqwest::Client::builder()
        .timeout(Duration::from_secs(60))
        .build()?;

    let mut northdata_cookie = std::env::var("NORTHDATA_COOKIE").ok();
    if let Some(ref path) = cli.northdata_cookie_file {
        northdata_cookie = Some(std::fs::read_to_string(path)?.trim().to_string());
    }

    let words_file = cli
        .randomize_words_file
        .unwrap_or_else(|| PathBuf::from("scripts/words.txt"));

    let cfg = GlobalRegistryPipelineConfig {
        engine,
        country_code: cc.clone(),
        output_csv: cli.output.clone(),
        kvk_api_url: cli.kvk_api_url.clone(),
        northdata_base_url: cli.northdata_base_url.clone(),
        northdata_cookie,
        min_query_len: cli.min_query_length,
        max_query_len: cli.max_query_length,
        query_seed: cli.query.clone().unwrap_or_default(),
        words_file,
        seed_csv_path: cli.randomize_seed_csv.clone(),
        randomize_no_seed_csv: cli.randomize_no_seed_csv,
        insert,
        max_workers: cli.max_workers,
        vat_id_search_engine: vat,
    };

    if cli.randomize_query {
        tracing::info!(
            "dexter-scrape: randomized loop ({:?}) → global_companies_registry",
            engine
        );
        run_randomized_registry_loop(http, dexter, cfg).await
    } else {
        let q = cli.query.unwrap_or_default();
        let q = q.trim();
        tracing::info!("dexter-scrape: single query ({:?})", engine);
        run_single_registry_pass(&http, dexter, &cfg, q, cli.append_csv).await
    }
}
