use clap::{Parser, Subcommand};
use std::path::{Path, PathBuf};

#[derive(Parser)]
#[command(name = "pmq-core", version, about = "PubMed XML parser (Rust engine)")]
struct Cli {
    #[command(subcommand)]
    command: Option<Commands>,
}

#[derive(Subcommand)]
enum Commands {
    /// Download and build PubMed Parquet database
    Sync(BuildArgs),
    /// Alias for sync
    Build(BuildArgs),
    /// Parse local .xml.gz files (no download)
    Parse {
        paths: Vec<PathBuf>,
        #[arg(long)] output: Option<PathBuf>,
        #[arg(long)] workers: Option<usize>,
    },
}

#[derive(clap::Args, Clone)]
struct BuildArgs {
    #[arg(long, alias = "output")]
    out_dir: Option<PathBuf>,
    #[arg(long)]
    cache_dir: Option<PathBuf>,
    #[arg(long)]
    workers: Option<usize>,
    #[arg(long)]
    dl_jobs: Option<usize>,
    #[arg(long)]
    no_baseline: bool,
    #[arg(long)]
    no_updates: bool,
    /// Skip pre-flight space check (for growable volumes)
    #[arg(long)]
    no_check: bool,
}

fn main() -> anyhow::Result<()> {
    let cli = Cli::parse();
    let dd = pmq::pipeline::default_data_dir();
    let dc = pmq::pipeline::default_cache_dir();

    match cli.command.unwrap_or(Commands::Sync(BuildArgs {
        out_dir: None, cache_dir: None, workers: None, dl_jobs: None,
        no_baseline: false, no_updates: false, no_check: false,
    })) {
        Commands::Sync(args) | Commands::Build(args) => {
            let out = args.out_dir.unwrap_or_else(|| dd.clone());
            let cache = args.cache_dir.unwrap_or_else(|| dc.clone());

            let (out, cache) = if args.no_check {
                (out, cache)
            } else {
                pmq::pipeline::preflight(&out, &cache)?
            };

            let mut c = pmq::pipeline::Config::auto(out, cache);
            if let Some(w) = args.workers { c.workers = w; }
            if let Some(d) = args.dl_jobs { c.dl_jobs = d; }
            c.baseline = !args.no_baseline;
            c.updates = !args.no_updates;
            eprintln!("[pmq] data:  {}", c.output_dir.display());
            eprintln!("[pmq] cache: {}", c.cache_dir.display());
            pmq::pipeline::run(&c)?;
        }
        Commands::Parse { paths, output, workers } => {
            let mut files: Vec<PathBuf> = Vec::new();
            for p in &paths {
                if p.is_dir() {
                    if let Ok(entries) = std::fs::read_dir(p) {
                        for e in entries.flatten() {
                            let path = e.path();
                            if path.extension().map(|x| x == "gz").unwrap_or(false) {
                                files.push(path);
                            }
                        }
                    }
                } else { files.push(p.clone()); }
            }
            files.sort();
            if files.is_empty() {
                eprintln!("No .xml.gz files found");
                return Ok(());
            }
            let cdir = files[0].parent().unwrap_or(Path::new(".")).to_path_buf();
            let mut c = pmq::pipeline::Config::auto(output.unwrap_or(dd), cdir);
            if let Some(w) = workers { c.workers = w; }
            pmq::pipeline::run_local(&c, files)?;
        }
    }
    Ok(())
}
