//! Matrix coverage for `create table T with pk [<col>(<type>)[, ...]]`
//! (ADR-0005, ADR-0009).

use crate::typing_surface::*;
use rdbms_playground::input_render::{AmbientHint, InputState};

#[test]
fn after_create_expects_table() {
    let schema = schema_empty();
    let a = assess_at_end("create ", &schema);
    assert!(matches!(a.state, InputState::IncompleteAtEof));
    assert_candidate_present(&a, &["table"]);
    crate::snap!("after_create", a);
}

#[test]
fn after_table_keyword_offers_no_candidates_for_new_name() {
    // The table-name slot is IdentSource::NewName — the user
    // invents the name, so no candidates from the schema. The
    // hint resolver surfaces a ForceProse "Type a name [then ...]"
    // affordance instead.
    let schema = schema_empty();
    let a = assess_at_end("create table ", &schema);
    assert!(matches!(a.state, InputState::IncompleteAtEof));
    assert!(
        matches!(&a.hint, Some(AmbientHint::Prose(_))),
        "expected Prose at NewName slot, got {:?}",
        a.hint,
    );
    crate::snap!("after_table_keyword", a);
}

#[test]
fn after_new_table_name_expects_with() {
    let schema = schema_empty();
    let a = assess_at_end("create table Customers ", &schema);
    assert!(matches!(a.state, InputState::IncompleteAtEof));
    assert_candidate_present(&a, &["with"]);
    crate::snap!("after_new_table_name", a);
}

#[test]
fn after_with_expects_pk() {
    let schema = schema_empty();
    let a = assess_at_end("create table Customers with ", &schema);
    assert!(matches!(a.state, InputState::IncompleteAtEof));
    assert_candidate_present(&a, &["pk"]);
    crate::snap!("after_with", a);
}

#[test]
fn create_table_with_pk_default_parses() {
    let schema = schema_empty();
    let a = assess_at_end("create table Customers with pk", &schema);
    assert!(matches!(a.state, InputState::Valid));
    assert_eq!(a.parse_result.as_deref(), Ok("CreateTable"));
    crate::snap!("with_pk_default", a);
}

#[test]
fn after_pk_word_does_not_re_offer_pk() {
    // Handoff-12 regression: at the cursor position right after
    // `with pk`, the completion engine must NOT re-offer `pk` as
    // a candidate. The full input parses and the partial-prefix
    // filter drops it.
    let schema = schema_empty();
    let a = assess_at_end("create table Customers with pk", &schema);
    let cands = completion_candidate_texts(&a);
    assert!(
        !cands.contains(&"pk".to_string()),
        "should NOT re-suggest `pk` (handoff-12 regression), got: {cands:?}",
    );
}

#[test]
fn after_pk_space_with_col_name_typed_expects_paren() {
    let schema = schema_empty();
    let a = assess_at_end("create table Customers with pk Code", &schema);
    assert!(matches!(a.state, InputState::IncompleteAtEof));
    crate::snap!("after_col_name", a);
}

#[test]
fn after_paren_expects_type_candidates() {
    let schema = schema_empty();
    let a = assess_at_end("create table Customers with pk Code(", &schema);
    assert!(matches!(a.state, InputState::IncompleteAtEof));
    assert_candidate_present(&a, &["text", "int", "serial", "shortid", "bool"]);
    crate::snap!("after_paren", a);
}

#[test]
fn create_table_with_explicit_pk_parses() {
    let schema = schema_empty();
    let a = assess_at_end("create table Customers with pk Code(text)", &schema);
    assert!(matches!(a.state, InputState::Valid));
    crate::snap!("with_explicit_pk", a);
}

#[test]
fn create_table_with_compound_pk_parses() {
    let schema = schema_empty();
    let a = assess_at_end(
        "create table Memberships with pk UserId(int), GroupId(int)",
        &schema,
    );
    assert!(matches!(a.state, InputState::Valid));
    crate::snap!("with_compound_pk", a);
}

#[test]
fn create_table_without_with_pk_is_incomplete() {
    // Tables need at least one column (parse.custom.
    // create_table_needs_pk) — submitting `create table T`
    // alone is rejected. Classification depends on whether the
    // walker treats `with pk` as required or optional at this
    // position.
    let schema = schema_empty();
    let a = assess_at_end("create table Customers", &schema);
    assert!(
        !matches!(a.state, InputState::Valid),
        "create table without `with pk` must not be Valid, got {:?}",
        a.state,
    );
    crate::snap!("no_with_pk", a);
}
