use std::path::PathBuf;

use clap::Args;
use obikindex::{KmerIndex, MergeMode};
use obikpartitionner::filter::{
    KmerFilter, MaxGenomeCount, MaxGenomeFraction, MaxTotalCount,
    MinGenomeCount, MinGenomeFraction, MinTotalCount,
};
use obisys::Reporter;
use obikseq::{set_k, set_m};
use tracing::info;

#[derive(Args)]
pub struct RebuildArgs {
    /// Source index directory
    pub source: PathBuf,

    /// Output index directory
    #[arg(short, long)]
    pub output: PathBuf,

    /// Minimum fraction of genomes containing the k-mer [0.0–1.0]
    #[arg(long)]
    pub min_quorum_frac: Option<f64>,

    /// Maximum fraction of genomes containing the k-mer [0.0–1.0]
    #[arg(long)]
    pub max_quorum_frac: Option<f64>,

    /// Minimum number of genomes containing the k-mer
    #[arg(long)]
    pub min_quorum_count: Option<usize>,

    /// Maximum number of genomes containing the k-mer
    #[arg(long)]
    pub max_quorum_count: Option<usize>,

    /// Minimum total count across all genomes (count index only)
    #[arg(long)]
    pub min_total_count: Option<u32>,

    /// Maximum total count across all genomes (count index only)
    #[arg(long)]
    pub max_total_count: Option<u32>,

    /// Per-genome count threshold for presence in quorum filters (default 0)
    #[arg(long, default_value = "0")]
    pub presence_threshold: u32,

    /// Output as presence/absence instead of counts
    #[arg(long)]
    pub presence: bool,

    /// Overwrite existing output directory
    #[arg(short, long)]
    pub force: bool,
}

pub fn run(args: RebuildArgs) {
    let src = KmerIndex::open(&args.source).unwrap_or_else(|e| {
        eprintln!("error opening source index: {e}");
        std::process::exit(1);
    });

    set_k(src.kmer_size());
    set_m(src.minimizer_size());

    let n_genomes = src.meta().genomes.len();
    let mode = if args.presence || !src.meta().config.with_counts {
        MergeMode::Presence
    } else {
        MergeMode::Count
    };

    info!(
        "rebuild: {} genome(s), mode={:?}, source={}",
        n_genomes, mode, args.source.display()
    );

    let pt = args.presence_threshold;
    let mut filters: Vec<Box<dyn KmerFilter>> = Vec::new();

    if let Some(v) = args.min_quorum_frac {
        filters.push(Box::new(MinGenomeFraction { frac: v, threshold: pt }));
    }
    if let Some(v) = args.max_quorum_frac {
        filters.push(Box::new(MaxGenomeFraction { frac: v, threshold: pt }));
    }
    if let Some(v) = args.min_quorum_count {
        filters.push(Box::new(MinGenomeCount { count: v, threshold: pt }));
    }
    if let Some(v) = args.max_quorum_count {
        filters.push(Box::new(MaxGenomeCount { count: v, threshold: pt }));
    }
    if let Some(v) = args.min_total_count {
        filters.push(Box::new(MinTotalCount { total: v }));
    }
    if let Some(v) = args.max_total_count {
        filters.push(Box::new(MaxTotalCount { total: v }));
    }

    let mut rep = Reporter::new();
    KmerIndex::rebuild(&args.output, &src, &filters, mode, args.force, &mut rep)
        .unwrap_or_else(|e| {
            eprintln!("error rebuilding index: {e}");
            std::process::exit(1);
        });

    rep.print();
    info!("rebuilt index → {}", args.output.display());
}
