use std::path::PathBuf;

use clap::Args;
use obikindex::{KmerIndex, MergeMode};
use obikpartitionner::filter::{MaxTotalCount, MinTotalCount};
use obisys::Reporter;
use tracing::info;

use super::predicate::FilterArgs as KmerFilterArgs;

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

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

    #[command(flatten)]
    pub filter: KmerFilterArgs,

    /// 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>,

    /// 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: FilterArgs) {
    let src = KmerIndex::open(&args.source).unwrap_or_else(|e| {
        eprintln!("error opening source index: {e}");
        std::process::exit(1);
    });

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

    info!(
        "filter: {} genome(s), mode={:?}, source={}",
        &src.meta().genomes.len(), mode, args.source.display()
    );

    let mut filters = args.filter.build_filters(&src.meta().genomes);

    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 filtering index: {e}");
            std::process::exit(1);
        });

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