//! Test suite for QueryEngine.

use std::sync::Arc;

use stemedb_core::testing::AssertionBuilder;
use stemedb_core::types::{Assertion, LifecycleStage, MaterializedView};
use stemedb_storage::{key_codec, GenericIndexStore, HybridStore, IndexStore, KVStore};

use super::QueryEngine;

mod alias_resolution;
mod basic;
mod changelog;
mod conflict_score;
mod indexes;
mod materialized_views;
mod similarity;
mod time_travel;

/// Helper to create a test assertion with standard values.
pub(super) fn create_test_assertion(
    subject: &str,
    predicate: &str,
    lifecycle: LifecycleStage,
) -> Assertion {
    AssertionBuilder::new()
        .subject(subject)
        .predicate(predicate)
        .confidence(0.95)
        .lifecycle(lifecycle)
        .build()
}

/// Helper to store an assertion in the KV store and update indexes.
pub(super) async fn store_assertion(store: &Arc<HybridStore>, assertion: &Assertion) {
    let bytes = stemedb_core::serde::serialize(assertion).expect("serialize");

    let hash = blake3::hash(&bytes);
    let key = key_codec::assertion_key(&assertion.subject, &hash.to_hex());
    store.put(&key, &bytes).await.expect("put");

    // Update indexes using IndexStore
    let index_store = GenericIndexStore::new(store.clone());
    let assertion_hash: [u8; 32] = *hash.as_bytes();
    index_store
        .add_to_indexes(&assertion.subject, &assertion.predicate, &assertion_hash)
        .await
        .expect("add to indexes");
}

/// Helper to store a materialized view directly in the KV store.
pub(super) async fn store_materialized_view(
    store: &Arc<HybridStore>,
    subject: &str,
    predicate: &str,
    winner: &Assertion,
) {
    store_materialized_view_with_time(store, subject, predicate, winner, 1000).await;
}

/// Helper to store a materialized view with a custom materialized_at timestamp.
pub(super) async fn store_materialized_view_with_time(
    store: &Arc<HybridStore>,
    subject: &str,
    predicate: &str,
    winner: &Assertion,
    materialized_at: u64,
) {
    let view = MaterializedView {
        winner: winner.clone(),
        lens_name: "VoteAwareConsensus".to_string(),
        resolution_confidence: 0.95,
        candidates_count: 3,
        materialized_at,
        conflict_score: 0.1,
    };

    let key = key_codec::mv_key(subject, predicate);
    let bytes = stemedb_core::serde::serialize(&view).expect("serialize MV");
    store.put(&key, &bytes).await.expect("put MV");
}
