//! Matrix coverage for completion-candidate *ordering*.
//!
//! The order candidates appear in is load-bearing for the hint
//! panel: the candidate line is single-row and window-scrolls
//! when it overflows, so whatever sits first is what stays
//! visible by default. Two invariants:
//!
//! 1. Connective keywords appear in grammar-declaration / reading
//!    order — `to` before `table` so `add column to table T`
//!    reads correctly, never the jarring `table` / `to`.
//! 2. Schema identifiers (table / column names) appear *before*
//!    command-part keywords. A name the user would otherwise
//!    have to look up is the highest-value completion — valuable
//!    even to experts, who come to know the keywords over time —
//!    so it must stay visible by default rather than scroll off
//!    behind the keyword run. (ADR-0022 Amendment 2; reverses the
//!    earlier handoff-14 keywords-first call, which held only
//!    while candidate lists were short.)
//!
//! These hold via declaration-order preservation +
//! identifiers-first sectioning in `candidates_at_cursor`.

use crate::typing_surface::*;

/// Index of `needle` in the ordered completion candidate list,
/// or panic with the full list for diagnosis.
fn pos(a: &Assessment, needle: &str) -> usize {
    let cands = completion_candidate_texts(a);
    cands
        .iter()
        .position(|c| c == needle)
        .unwrap_or_else(|| panic!("{needle:?} not in candidates: {cands:?}"))
}

/// Assert `first` appears before `second` in the candidate list.
fn assert_before(a: &Assessment, first: &str, second: &str) {
    let pf = pos(a, first);
    let ps = pos(a, second);
    assert!(
        pf < ps,
        "expected {first:?} (idx {pf}) before {second:?} (idx {ps}): {:?}",
        completion_candidate_texts(a),
    );
}

// =========================================================
// Connective ordering: the `[connective] [table] <T>` shape
// shared by the DDL commands.
// =========================================================

#[test]
fn add_column_lists_to_before_table() {
    let schema = schema_multi_table();
    let a = assess_at_end("add column ", &schema);
    assert_before(&a, "to", "table");
    crate::snap!("add_column_connectives", a);
}

#[test]
fn drop_column_lists_from_before_table() {
    let schema = schema_multi_table();
    let a = assess_at_end("drop column ", &schema);
    assert_before(&a, "from", "table");
    crate::snap!("drop_column_connectives", a);
}

#[test]
fn rename_column_lists_in_before_table() {
    let schema = schema_multi_table();
    let a = assess_at_end("rename column ", &schema);
    assert_before(&a, "in", "table");
    crate::snap!("rename_column_connectives", a);
}

#[test]
fn change_column_lists_in_before_table() {
    let schema = schema_multi_table();
    let a = assess_at_end("change column ", &schema);
    assert_before(&a, "in", "table");
    crate::snap!("change_column_connectives", a);
}

// =========================================================
// Identifiers-before-keywords: at a position where both a
// connective keyword and schema table names are valid, the
// schema identifiers come first (ADR-0022 Amendment 2).
// =========================================================

#[test]
fn add_column_identifiers_precede_table_keywords() {
    let schema = schema_multi_table();
    let a = assess_at_end("add column ", &schema);
    // Customers / Orders are schema identifiers; `to` / `table`
    // are command parts — every ident precedes every keyword.
    assert_before(&a, "Customers", "table");
    assert_before(&a, "Customers", "to");
    assert_before(&a, "Orders", "to");
    crate::snap!("add_column_idents_then_keyword", a);
}

#[test]
fn drop_column_identifiers_precede_table_keywords() {
    let schema = schema_multi_table();
    let a = assess_at_end("drop column ", &schema);
    assert_before(&a, "Customers", "table");
    assert_before(&a, "Orders", "from");
    crate::snap!("drop_column_idents_then_keyword", a);
}

#[test]
fn insert_into_table_keyword_precedes_nothing_when_only_idents() {
    // Sanity: at `insert into ` only table identifiers are
    // valid — no keyword to precede them, but the ordering must
    // still be deterministic (alphabetical among idents).
    let schema = schema_multi_table();
    let a = assess_at_end("insert into ", &schema);
    assert_before(&a, "Customers", "Orders");
    crate::snap!("insert_into_idents_only", a);
}

// =========================================================
// After consuming the first connective, identifiers still
// surface ahead of the remaining keyword.
// =========================================================

#[test]
fn add_column_after_to_lists_identifiers_before_table() {
    let schema = schema_multi_table();
    let a = assess_at_end("add column to ", &schema);
    assert_before(&a, "Customers", "table");
    crate::snap!("add_column_after_to", a);
}
