use clap::Parser;
use std::collections::HashMap;
use std::env::set_var;
use std::io::Result;
use std::sync::RwLock;

use dexter_sentinel::config::ScraperConfig;
use dexter_sentinel::data::{scraper_overrides, Provider};
use dexter_sentinel::persisted_config::{self, StoredConnection};
use dexter_sentinel::run_server;

#[derive(Parser, Debug)]
#[command(
    name = "dexter-sentinel",
    about = "Config-driven HTTP scrape API",
    long_about = "Config-driven HTTP scrape API.\n\n\
Athena and Redis connection settings are merged from: (1) CLI flags, (2) environment variables, \
(3) credentials.json under the OS local data directory (e.g. Windows: %LOCALAPPDATA%\\dexter-sentinel\\, \
Linux: ~/.local/share/dexter-sentinel/, macOS: ~/Library/Application Support/dexter-sentinel/). \
CLI and env override the file. When any of these values is set after merge, the merged result is saved."
)]
struct Cli {
    #[arg(long, env = "HOST", default_value = "0.0.0.0")]
    host: String,

    #[arg(long, env = "PORT", default_value_t = 8080)]
    port: u16,

    #[arg(long, env = "REDIS_URL")]
    redis_url: Option<String>,

    #[arg(long, env = "ATHENA_URL")]
    athena_url: Option<String>,

    #[arg(long, env = "ATHENA_API_KEY", hide_env_values = true)]
    athena_key: Option<String>,

    /// Value of the X-Athena-Client header (defaults to `dexter` when unset).
    #[arg(long, env = "ATHENA_CLIENT")]
    athena_client: Option<String>,

    /// Fetch scraper overrides from Athena into an empty cache and exit (connectivity check).
    #[arg(long)]
    prefetch_scraper_overrides: bool,
}

fn apply_merged_connection(conn: &StoredConnection) {
    if let Some(url) = conn.redis_url.as_ref() {
        set_var("REDIS_URL", url);
    }
    if let Some(url) = conn.athena_url.as_ref() {
        set_var("ATHENA_URL", url);
    }
    if let Some(key) = conn.athena_key.as_ref() {
        set_var("ATHENA_API_KEY", key);
    }
    if let Some(client) = conn.athena_client.as_ref() {
        set_var("ATHENA_CLIENT", client);
    }
}

#[actix_web::main]
async fn main() -> Result<()> {
    dotenv::dotenv().ok();
    let cli: Cli = Cli::parse();

    set_var("HOST", &cli.host);
    set_var("PORT", cli.port.to_string());

    let from_disk: StoredConnection = persisted_config::load();
    let from_cli: StoredConnection = StoredConnection {
        redis_url: cli.redis_url.clone(),
        athena_url: cli.athena_url.clone(),
        athena_key: cli.athena_key.clone(),
        athena_client: cli.athena_client.clone(),
    };
    let merged: StoredConnection = StoredConnection::merge_with_cli_and_file(&from_cli, from_disk);
    apply_merged_connection(&merged);
    if let Err(e) = persisted_config::save(&merged) {
        eprintln!(
            "warning: could not write {}: {}",
            persisted_config::credentials_path_display(),
            e
        );
    }

    if cli.prefetch_scraper_overrides {
        let Some(provider) = Provider::new().await else {
            eprintln!("Athena not configured (ATHENA_URL and ATHENA_API_KEY)");
            std::process::exit(1);
        };
        let cache: RwLock<HashMap<String, ScraperConfig>> = RwLock::new(HashMap::new());
        match scraper_overrides::sync_scraper_overrides(provider.client.as_ref(), &cache).await {
            Ok(n) => {
                println!("Loaded {} scraper override(s) from Athena", n);
                std::process::exit(0);
            }
            Err(e) => {
                eprintln!("{}", e);
                std::process::exit(1);
            }
        }
    }

    run_server().await
}
