//! Segment merge profiling.

use super::harness::*;
use luci_index::merge::merge_segments;
use luci_index::deletion::DeletionMap;
use luci_index::reader::IndexReader;
use luci_index::segment::reader::SegmentReader;
use luci_analysis::AnalyzerRegistry;
use luci_storage::SingleFileDirectory;

use std::time::Instant;

#[test]
fn merge_time_by_segment_count() {
    println!("\n=== Merge: Time by Segment Count (1K docs each) ===\n");

    for &segs in &[2, 5, 10] {
        let (path, _index) = build_multi_segment_corpus(
            &format!("merge_{segs}seg"), segs, 1_000,
        );

        let storage = SingleFileDirectory::open(&path).unwrap();
        let reader = IndexReader::open(&storage).unwrap();
        let segments: Vec<SegmentReader> = storage.segments().iter()
            .map(|e| SegmentReader::open(storage.read_segment(e.segment_id).unwrap()).unwrap())
            .collect();

        let refs: Vec<&SegmentReader> = segments.iter().collect();
        let deletions = DeletionMap::new();

        let start = Instant::now();
        let _merged = merge_segments(
            luci_core::SegmentId::new(999),
            &refs,
            &deletions,
            &text_schema(),
            &AnalyzerRegistry::new(),
        );
        let elapsed = start.elapsed();
        let total_docs = segs * 1_000;

        println!("{segs:>2} segments ({total_docs} docs): {:.0}ms ({:.0} docs/s)",
            elapsed.as_millis(),
            total_docs as f64 / elapsed.as_secs_f64());

        cleanup(&path);
    }
}

#[test]
fn merge_time_by_doc_count() {
    println!("\n=== Merge: Time by Document Count (2 segments) ===\n");

    for &docs_per in &[500, 2_500, 5_000, 10_000] {
        let (path, _index) = build_multi_segment_corpus(
            &format!("merge_2x{docs_per}"), 2, docs_per,
        );

        let storage = SingleFileDirectory::open(&path).unwrap();
        let segments: Vec<SegmentReader> = storage.segments().iter()
            .map(|e| SegmentReader::open(storage.read_segment(e.segment_id).unwrap()).unwrap())
            .collect();

        let refs: Vec<&SegmentReader> = segments.iter().collect();
        let deletions = DeletionMap::new();
        let total = docs_per * 2;

        let start = Instant::now();
        let _merged = merge_segments(
            luci_core::SegmentId::new(999),
            &refs,
            &deletions,
            &text_schema(),
            &AnalyzerRegistry::new(),
        );
        let elapsed = start.elapsed();

        println!("2 x {docs_per:>6} docs ({total:>6} total): {:.0}ms ({:.0} docs/s)",
            elapsed.as_millis(),
            total as f64 / elapsed.as_secs_f64());

        cleanup(&path);
    }
}

#[test]
fn merge_with_deletions() {
    println!("\n=== Merge: With Deletions (2 x 5K docs) ===\n");

    for &delete_pct in &[0, 10, 25, 50, 90] {
        let (path, _index) = build_multi_segment_corpus(
            &format!("merge_del_{delete_pct}pct"), 2, 5_000,
        );

        let storage = SingleFileDirectory::open(&path).unwrap();
        let segments: Vec<SegmentReader> = storage.segments().iter()
            .map(|e| SegmentReader::open(storage.read_segment(e.segment_id).unwrap()).unwrap())
            .collect();

        let mut deletions = DeletionMap::new();
        let total_docs = 10_000usize;
        let delete_count = total_docs * delete_pct / 100;

        // Delete every Nth doc from each segment
        for (seg_idx, seg) in segments.iter().enumerate() {
            let seg_id = seg.segment_id();
            let per_seg = delete_count / 2;
            let step = if per_seg > 0 { 5_000 / per_seg } else { usize::MAX };
            for d in (0..5_000).step_by(step.max(1)).take(per_seg) {
                deletions.mark_deleted(seg_id, luci_core::DocId::new(d as u32));
            }
        }

        let refs: Vec<&SegmentReader> = segments.iter().collect();

        let start = Instant::now();
        let merged = merge_segments(
            luci_core::SegmentId::new(999),
            &refs,
            &deletions,
            &text_schema(),
            &AnalyzerRegistry::new(),
        );
        let elapsed = start.elapsed();
        let merged_reader = SegmentReader::open(merged).unwrap();
        let surviving = merged_reader.doc_count();

        println!("{delete_pct:>3}% deleted: {:.0}ms → {surviving} docs surviving",
            elapsed.as_millis());

        cleanup(&path);
    }
}
