//! Shared test fixtures for the RETRIEVE executor unit tests.
//!
//! `tests.rs` and `tests_part2.rs` were split solely to keep each file under the
//! ≤ 600-line cap (`CODING_GUIDELINES` §9), but both need the SAME scaffolding:
//! a minimal schema, the built-in profile registry, an item-insertion helper,
//! and an executor constructor. Rather than copy-paste these verbatim across the
//! two modules (a DRY hazard — a fix to one fixture silently skips the other),
//! they live here once and are imported via `use super::test_support::*`.

#![cfg(test)]
#![allow(clippy::unwrap_used)]

use std::{sync::RwLock, time::Duration};

use roaring::RoaringBitmap;

use super::RetrieveExecutor;
use crate::{
    ranking::{builtins::register_builtins, registry::ProfileRegistry},
    schema::{DecaySpec, EntityKind, SchemaBuilder, Timestamp, Window},
    signals::SignalLedger,
    storage::indexes::{bitmap::BitmapIndex, range::RangeIndex},
};

/// Minimal item schema: the generic signal vocabulary the built-in profiles read.
pub(super) fn test_schema() -> crate::schema::Schema {
    let mut builder = SchemaBuilder::new();
    for sig in &["view", "like", "share", "skip", "completion"] {
        let _ = builder
            .signal(
                sig,
                EntityKind::Item,
                DecaySpec::Exponential {
                    half_life: Duration::from_secs(7 * 24 * 3600),
                },
            )
            .windows(&[Window::OneHour, Window::TwentyFourHours, Window::SevenDays])
            .velocity(true)
            .add();
    }
    builder.build().unwrap()
}

/// Profile registry pre-loaded with the built-in profiles.
pub(super) fn setup_registry() -> ProfileRegistry {
    let mut reg = ProfileRegistry::new();
    register_builtins(&mut reg).unwrap();
    reg
}

/// Add an item to the in-memory indexes and universe bitmap.
#[allow(clippy::too_many_arguments)]
pub(super) fn add_item(
    category_idx: &BitmapIndex,
    format_idx: &BitmapIndex,
    creator_idx: &BitmapIndex,
    duration_idx: &RangeIndex<u32>,
    created_at_idx: &RangeIndex<u64>,
    universe: &mut RoaringBitmap,
    id: u64,
    category: &str,
    format: &str,
    creator: u64,
) {
    let id_u32 = id as u32;
    category_idx.insert(id_u32, category);
    format_idx.insert(id_u32, format);
    creator_idx.insert(id_u32, creator.to_string());
    duration_idx.insert(id_u32, 0u32);
    created_at_idx.insert(id_u32, Timestamp::now().as_nanos());
    universe.insert(id_u32);
}

/// Build an executor from test indexes.
#[allow(clippy::too_many_arguments)]
pub(super) fn make_executor<'a>(
    ledger: &'a SignalLedger,
    profile_reg: &'a ProfileRegistry,
    cat: &'a BitmapIndex,
    fmt: &'a BitmapIndex,
    creator: &'a BitmapIndex,
    tag: &'a BitmapIndex,
    dur: &'a RangeIndex<u32>,
    ts: &'a RangeIndex<u64>,
    universe: &'a RwLock<RoaringBitmap>,
) -> RetrieveExecutor<'a> {
    RetrieveExecutor::new(
        ledger,
        profile_reg,
        Some(cat),
        Some(fmt),
        Some(creator),
        Some(tag),
        Some(dur),
        Some(ts),
        Some(universe),
    )
}
