//! Registry of reserved keywords.
//!
//! Single source of truth for the keyword list in
//! `docs/src/reference/keywords.md`, generated by [`render_markdown`]. The test
//! `tests/keywords_reference.rs` asserts this table matches exactly the
//! alphabetic `#[token("…")]` keywords declared in `lexer.rs`, so the two
//! cannot drift.

/// One reserved keyword and a one-line description of its role.
pub struct KeywordInfo {
    pub word: &'static str,
    pub meaning: &'static str,
}

/// Every reserved keyword, sorted.
pub const KEYWORDS: &[KeywordInfo] = &[
    k("Bool", "The boolean base type."),
    k(
        "Duration",
        "The time-span base type, in milliseconds (`5.minutes`).",
    ),
    k("Effect", "The effectful-computation type, `Effect[T]`."),
    k("Err", "The error variant of `Result`."),
    k("Float", "The floating-point base type."),
    k(
        "Instant",
        "The absolute-time base type, in epoch milliseconds (`Clock.now()`).",
    ),
    k("Int", "The integer base type."),
    k(
        "JsonError",
        "The JSON-decode error type, `Result[T, JsonError]` from `Json.decode`.",
    ),
    k("None", "The empty variant of `Option`."),
    k("Ok", "The success variant of `Result`."),
    k("Option", "The optional-value type, `Option[T]`."),
    k("Result", "The success-or-error type, `Result[T, E]`."),
    k("Some", "The present variant of `Option`."),
    k("String", "The string base type."),
    k(
        "ValidationError",
        "The error type returned by a refined type's `.of`.",
    ),
    k(
        "actor",
        "Declare an actor — a boundary contract a handler consumes via `by`.",
    ),
    k(
        "adapter",
        "Declare an adapter — the host boundary (capability contract + binding).",
    ),
    k("agent", "Declare a stateful, keyed agent inside a context."),
    k("and", "Combine refinement predicates (`where A and B`)."),
    k("as", "Alias a consumed context (`consumes X as Y`)."),
    k("assert", "Assert a condition inside a test case."),
    k(
        "binding",
        "Name an adapter's TypeScript binding module (`binding \"<module>\"`).",
    ),
    k(
        "by",
        "Name the actor a handler consumes (`on … by <name>: <Actor>`).",
    ),
    k(
        "capability",
        "Declare a capability (a dependency interface) in a context.",
    ),
    k(
        "commons",
        "Declare a pure, stateless module of types and functions.",
    ),
    k(
        "consumes",
        "Declare a dependency on another context's services.",
    ),
    k(
        "context",
        "Declare a deployable context (services, agents, capabilities).",
    ),
    k(
        "cron",
        "The cron protocol on a service header (`from cron`).",
    ),
    k("else", "The alternative branch of an `if` expression."),
    k("enum", "Declare a payloadless sum type (`enum { A, B }`)."),
    k("expect", "Reserved keyword."),
    k("exports", "Declare which types a context exposes, and how."),
    k("false", "The boolean literal `false`."),
    k("fn", "Declare a function."),
    k(
        "from",
        "Name the protocol a service conforms to (`service X from http`).",
    ),
    k("given", "Declare the capabilities a handler requires."),
    k(
        "http",
        "The HTTP protocol on a service header (`from http`).",
    ),
    k("if", "A conditional expression."),
    k(
        "implies",
        "Logical implication (`P implies Q` ≡ `!P || Q`), used in invariant predicates.",
    ),
    k(
        "invariant",
        "Declare an agent invariant — a predicate that must hold of every committed state.",
    ),
    k(
        "is",
        "Test a value against a variant pattern, yielding a `Bool`.",
    ),
    k(
        "let",
        "Bind a local value (`let x = …`, or `let x <- …` for an effect).",
    ),
    k(
        "match",
        "Pattern-match over a sum type, `Result`, or `Option`.",
    ),
    k(
        "mocks",
        "Provide a mock capability implementation in a test.",
    ),
    k(
        "on",
        "Begin a handler declaration (`on call`, `on GET(…)`, `on message`).",
    ),
    k(
        "opaque",
        "Declare an opaque type, or export a type opaquely.",
    ),
    k(
        "protocol",
        "Reserved keyword (protocols are a closed, compiler-known set).",
    ),
    k("provides", "Provide an implementation of a capability."),
    k(
        "queue",
        "The queue protocol on a service header (`from queue(\"name\")`).",
    ),
    k(
        "record",
        "Reserved keyword (records are written `type X = { … }`).",
    ),
    k("self", "The current agent instance, inside a handler."),
    k(
        "service",
        "Declare a service (a group of handlers) in a context.",
    ),
    k("test", "Declare a test block or a test case."),
    k(
        "transparent",
        "Export a type with its structure visible (`exports transparent { … }`).",
    ),
    k("true", "The boolean literal `true`."),
    k(
        "type",
        "Declare a type: alias, record, sum, opaque, or refined.",
    ),
    k("uses", "Bring a commons into scope."),
    k("where", "Attach refinement predicates to a base type."),
    k(
        "wires",
        "List the contexts a `test integration` stands up as Workers.",
    ),
];

const fn k(word: &'static str, meaning: &'static str) -> KeywordInfo {
    KeywordInfo { word, meaning }
}

/// Render the keyword list as a Markdown reference page.
pub fn render_markdown() -> String {
    let mut out = String::new();
    out.push_str("# Keywords\n\n");
    out.push_str(
        "<!-- GENERATED FILE — do not edit by hand.\n     \
         Source: bynkc/src/keywords.rs (`render_markdown`).\n     \
         Regenerate with: BYNK_BLESS=1 cargo test -p bynkc --test keywords_reference -->\n\n",
    );
    out.push_str(
        "Every reserved keyword, with a one-line description. Reserved words cannot \
         be used as identifiers.\n\n",
    );
    out.push_str(&format!(
        "There are **{}** reserved keywords.\n\n",
        KEYWORDS.len()
    ));
    out.push_str("| Keyword | Meaning |\n|---|---|\n");
    for info in KEYWORDS {
        out.push_str(&format!("| `{}` | {} |\n", info.word, info.meaning));
    }
    out
}
