# AUTO-GENERATED -- DO NOT EDIT.
#
# This file is regenerated by `scripts/regen-bindings.sh` from the
# JSON Schema at `crates/rustledger-wasm/bindings/index.schema.json`,
# which in turn comes from the Rust DTOs in
# `crates/rustledger-wasm/src/types.rs`. CI fails if this file drifts.
# See ADR-0004 (#1218 + #1232 for Phase 3) for the design.

from __future__ import annotations

from typing import Literal

from pydantic import BaseModel, Field, RootModel



class AmountValue(BaseModel):
    """
    Amount value for serialization.
    """

    currency: str = Field(..., description="The currency.")
    number: str = Field(..., description="The number as a string.")


class CellValue1(BaseModel):
    """
    Amount with number and currency.
    """

    currency: str
    number: str


class CompletionJson(BaseModel):
    """
    BQL completion suggestion for WASM.
    """

    category: str = Field(
        ..., description="Category: keyword, function, column, operator, literal."
    )
    description: str | None = Field(
        None, description="Optional description/documentation."
    )
    text: str = Field(..., description="The completion text to insert.")


class CompletionKind(RootModel[str]):
    root: str = Field(..., description="The kind of a completion item.")


class CompletionResultJson(BaseModel):
    """
    Result of BQL completion request.
    """

    completions: list[CompletionJson] = Field(..., description="List of completions.")
    context: str = Field(..., description="Current context for debugging.")


class CostNumberJson1(BaseModel):
    """
    Per-unit cost (e.g., `{100 USD}`).
    """

    kind: Literal["per_unit"]
    value: str = Field(..., description="Per-unit value.")


class CostNumberJson2(BaseModel):
    """
    Total cost as written (e.g., `{{1000 USD}}`), pre-booking.
    """

    kind: Literal["total"]
    value: str = Field(..., description="Total value.")


class CostNumberJson3(BaseModel):
    """
    Post-booking derived per-unit with preserved source total.
    """

    kind: Literal["per_unit_from_total"]
    per_unit: str = Field(..., description="Derived per-unit.")
    total: str = Field(..., description="Source total.")


class CostNumberJson(RootModel[CostNumberJson1 | CostNumberJson2 | CostNumberJson3]):
    root: CostNumberJson1 | CostNumberJson2 | CostNumberJson3 = Field(
        ...,
        description="Wire-format of the numeric component of a [`PostingCostJson`].\n\nMirrors `rustledger_core::CostNumber` on the wire so JS consumers\nsee the same mutual exclusion the host enforces. Use the `kind`\nfield as the discriminator.",
    )


class CostValue(BaseModel):
    """
    Cost value for serialization.
    """

    currency: str = Field(..., description="Cost currency.")
    date: str | None = Field(None, description="Acquisition date.")
    label: str | None = Field(None, description="Lot label.")
    number: str = Field(..., description="Cost per unit.")


class EditorCompletion(BaseModel):
    """
    A completion item for Beancount source editing.
    """

    detail: str | None = Field(
        None, description="A human-readable string with additional information."
    )
    insert_text: str | None = Field(
        None, description="The text to insert when this completion is selected."
    )
    kind: CompletionKind = Field(..., description="The kind of completion item.")
    label: str = Field(..., description="The label to display in the completion list.")


class EditorCompletionResult(BaseModel):
    """
    Result of a completion request.
    """

    completions: list[EditorCompletion] = Field(..., description="The completions.")
    context: str = Field(..., description="The detected context.")


class EditorLocation(BaseModel):
    """
    A location in the document.
    """

    character: int = Field(..., description="Character offset (0-based).", ge=0)
    line: int = Field(..., description="Line number (0-based).", ge=0)


class EditorRange(BaseModel):
    """
    A range in the document.
    """

    end_character: int = Field(..., description="End character (0-based).", ge=0)
    end_line: int = Field(..., description="End line (0-based).", ge=0)
    start_character: int = Field(..., description="Start character (0-based).", ge=0)
    start_line: int = Field(..., description="Start line (0-based).", ge=0)


class LedgerOptions(BaseModel):
    """
    Ledger options.
    """

    operating_currencies: list[str] = Field(..., description="Operating currencies.")
    title: str | None = Field(
        ...,
        description="Ledger title. Emitted as JSON `null` when no title is set\n(no `skip_serializing_if`; field is always present on the\nwire). TS: `string | null`, not `title?`. The required-and-\nnullable wire contract is enforced via the `schemars(extend)`\non the struct itself; see `ParseResult` for the rationale.",
    )


class MetaValueJson1(BaseModel):
    """
    Amount values (`{number, currency}`) — the only structured
    shape that survives the round-trip. Same `{number, currency}`
    envelope as [`AmountValue`] so JS consumers can branch on
    shape without a discriminator tag.

    **Deserialize note**: serde's untagged-enum matcher accepts
    extra fields in a JSON object (`#[serde(deny_unknown_fields)]`
    can't be applied per-variant on an untagged enum without
    breaking the wider match). A JS client sending
    `{number: "100", currency: "USD", extra: "x"}` deserializes as
    `Amount { number: "100", currency: "USD" }` with `extra`
    silently dropped. Output-side consumers (the production path)
    are unaffected; treat `Deserialize` here as best-effort and
    validate at the host boundary if you need stricter checks.
    """

    currency: str = Field(..., description="The currency code.")
    number: str = Field(
        ..., description="The decimal quantity, stringified for precision."
    )


class MetaValueJson(RootModel[str | bool | MetaValueJson1 | None]):
    root: str | bool | MetaValueJson1 | None = Field(
        ...,
        description="Metadata-value wire format for WASM consumers.\n\n**JSON output is byte-equivalent to FFI-WASI's\n`meta_value_to_json`** — JS clients writing portable code see\nidentical metadata values from both bindings. The Rust-side\ntypes are independent though: FFI-WASI emits\n`serde_json::Value` (untyped), this crate emits a typed enum.\nUnifying the source-of-truth is tracked by issue #1200 item 2.\n\nThe host's [`rustledger_core::MetaValue`] is richer than the wire\ntype — `Account`/`Currency`/`Tag`/`Link`/`Date`/`Number` all\nflatten to JSON strings here, matching FFI-WASI behavior. JS\nconsumers that need the strong type info should query the host\nvia a typed API; this enum is the lossy-but-portable view.\n\nUntagged on the wire: `\"hello\"` serializes as a string,\n`true` as a boolean, `null` as null, and an [`AmountValue`]\n`{number,currency}` as a plain object. The TypeScript union is\n`Record<string, string | boolean | {number, currency} | null>` —\nno raw JSON number arm because `MetaValue::Number` (`Decimal`)\nstringifies to preserve precision. Issue #1168 proposed\n`string | number | boolean | null`; we substitute the\n`{number,currency}` shape for `number` so cost-bearing metadata\nround-trips cleanly and so JS numeric literals don't silently\nalias into the wire (see the `meta_value_json_rejects_raw_json_number`\ntest).",
    )


class PluginInfo(BaseModel):
    """
    Plugin information.
    """

    description: str = Field(..., description="Plugin description.")
    name: str = Field(..., description="Plugin name.")


class PositionValue(BaseModel):
    """
    Position value for serialization.
    """

    units: AmountValue = Field(..., description="The units.")


class PostingCostJson(BaseModel):
    """
    A posting cost in JSON-serializable form.
    """

    currency: str | None = Field(None, description="Cost currency.")
    date: str | None = Field(None, description="Acquisition date.")
    label: str | None = Field(None, description="Lot label.")
    number: CostNumberJson | None = Field(
        None, description="Cost number (per-unit, total, or post-booking pair)."
    )


class PostingJson(BaseModel):
    """
    A posting in JSON-serializable form.
    """

    account: str = Field(..., description="Account name.")
    cost: PostingCostJson | None = Field(None, description="Cost specification.")
    flag: str | None = Field(
        None,
        description='Posting-level flag (e.g., `"!"` for pending). Mirrors\n`rustledger_core::Posting::flag`.',
    )
    meta: dict[str, MetaValueJson] | None = Field(
        None,
        description="Posting-level metadata (issue #1168). Empty when the posting\nhas no explicit metadata.",
    )
    price: AmountValue | None = Field(None, description="Price annotation.")
    units: AmountValue | None = Field(None, description="Units (amount).")


class ReferenceKind(RootModel[str]):
    root: str = Field(..., description="The kind of symbol being referenced.")


class Severity(RootModel[str]):
    root: str = Field(..., description="Error severity level.")


class SymbolKind(RootModel[str]):
    root: str = Field(..., description="The kind of a symbol.")


class TypedValueJson(BaseModel):
    """
    Tagged-union wire-format for a [`rustledger_core::MetaValue`] that
    preserves the host's variant tag.

    Used **only** in `DirectiveJson::Custom`'s `values` field, where
    callers genuinely need to distinguish (for example) a `Date` from
    a `String` or an `Account` — all three of which collapse to a bare
    JSON string under the untagged [`MetaValueJson`] shape.

    Wire shape: `{"type": "<variant>", "value": ...}` — mirrors
    `rustledger-ffi-wasi::TypedValue` (see
    `crates/rustledger-ffi-wasi/src/types/output.rs::TypedValue`) so
    portable JS consumers see identical envelopes across both bindings.

    **Why `value: MetaValueJson` and not `serde_json::Value`** —
    `serde_json` is intentionally a host-only dev-dependency for this
    crate (the runtime build avoids it to keep the wasm32 dep chain
    small). [`MetaValueJson`] already covers every payload shape
    FFI-WASI's `TypedValue` emits: `String` for the string-flavored
    variants, `Bool` for `bool`, `Amount` for `amount`, `Null` for
    `null`. The serialized JSON is bit-identical to FFI-WASI's.

    `MetaValueJson` (untagged) is retained for the `meta` map of every
    directive — there the lossy shape is intentional and matches what
    FFI-WASI's metadata side also emits.

    **Breaking change from #1199** for the WASM binding: pre-#1207
    `Custom.values` emitted raw `MetaValueJson` values (lossy). Closes
    #1207.
    """

    type: str = Field(
        ...,
        description='Variant tag — one of `"string"`, `"account"`, `"currency"`,\n`"tag"`, `"link"`, `"date"`, `"number"`, `"bool"`, `"amount"`,\n`"null"`. Matches FFI-WASI\'s tag strings exactly.\n\nRenamed via `#[ts(type = ...)]` so the discriminator is a\nstring-literal union on the TS side. The post-process script\nfurther narrows the full struct shape into a discriminated\nunion (per-variant `{type, value}` rows) -- see ADR-0004 for\nwhy the narrowing is hand-tuned rather than generator-driven.',
    )
    value: MetaValueJson = Field(
        ..., description="Variant payload (see [`MetaValueJson`] for the four shapes)."
    )


class BeancountError(BaseModel):
    """
    An error with source location.

    **Renamed to `BeancountError` on the TS side** to avoid shadowing
    the JS-builtin `Error` type. The Rust struct keeps the shorter
    `Error` name for internal use; the rename is applied via
    `#[ts(rename = ...)]` so consumers see a non-shadowing name.
    """

    column: int | None = Field(
        ...,
        description="Column number (1-based). `null` when the error has no source\nlocation. See `line` above for `range` rationale.",
        ge=1,
    )
    line: int | None = Field(
        ...,
        description="Line number (1-based). `null` when the error has no source\nlocation (e.g. validation errors not tied to a span). Field is\nalways present on the wire (no `skip_serializing_if`); see the\nstruct-level `schemars(extend)` for the required-and-nullable\nrationale. `range(min = 1)` enforces the 1-based documented\ncontract on the JSON Schema side (schemars defaults to\n`minimum: 0` for u32).",
        ge=1,
    )
    message: str = Field(..., description="Error message.")
    severity: Severity = Field(..., description="Error severity.")


class CellValue2(BaseModel):
    """
    Position with units and optional cost.
    """

    cost: CostValue | None = None
    units: AmountValue


class CellValue3(BaseModel):
    """
    Inventory with positions.
    """

    positions: list[PositionValue]


class CellValue(
    RootModel[
        str
        | int
        | bool
        | CellValue1
        | CellValue2
        | CellValue3
        | list[str]
        | list[CellValue]
        | dict[str, CellValue]
        | None
    ]
):
    root: (
        str
        | int
        | bool
        | CellValue1
        | CellValue2
        | CellValue3
        | list[str]
        | list[CellValue]
        | dict[str, CellValue]
        | None
    ) = Field(
        ...,
        description="A cell value that serializes properly to JavaScript.\n\nUses untagged serialization to produce clean JSON output.",
    )


class DirectiveJson1(BaseModel):
    """
    Transaction directive.
    """

    date: str
    flag: str
    links: list[str]
    meta: dict[str, MetaValueJson] | None = None
    narration: str | None = Field(
        None,
        description="Optional narration. Empty narrations are normalized to\n`None` in `convert.rs` so the field is absent on the wire\nin the empty case -- matches FFI-WASI's pattern (#1221).",
    )
    payee: str | None = Field(
        None,
        description="Optional payee. Mirrors FFI-WASI's shape: absent on the\nwire when `None` (closes #1221).",
    )
    postings: list[PostingJson]
    tags: list[str]
    type: Literal["transaction"]


class DirectiveJson2(BaseModel):
    """
    Balance assertion.
    """

    account: str
    amount: AmountValue
    date: str
    meta: dict[str, MetaValueJson] | None = None
    tolerance: str | None = Field(
        None,
        description="Explicit tolerance from the `~ 0.01` annotation, stringified.\nMirrors `rustledger_core::Balance::tolerance`.",
    )
    type: Literal["balance"]


class DirectiveJson3(BaseModel):
    """
    Open account.
    """

    account: str
    booking: str | None = None
    currencies: list[str]
    date: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["open"]


class DirectiveJson4(BaseModel):
    """
    Close account.
    """

    account: str
    date: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["close"]


class DirectiveJson5(BaseModel):
    """
    Commodity declaration.
    """

    currency: str
    date: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["commodity"]


class DirectiveJson6(BaseModel):
    """
    Pad directive.
    """

    account: str
    date: str
    meta: dict[str, MetaValueJson] | None = None
    source_account: str
    type: Literal["pad"]


class DirectiveJson7(BaseModel):
    """
    Event directive.
    """

    date: str
    event_type: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["event"]
    value: str


class DirectiveJson8(BaseModel):
    """
    Note directive.
    """

    account: str
    comment: str
    date: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["note"]


class DirectiveJson9(BaseModel):
    """
    Document directive.
    """

    account: str
    date: str
    links: list[str] | None = Field(
        None, description="Links attached to the document directive (issue #1144)."
    )
    meta: dict[str, MetaValueJson] | None = None
    path: str
    tags: list[str] | None = Field(
        None, description="Tags attached to the document directive (issue #1144)."
    )
    type: Literal["document"]


class DirectiveJson10(BaseModel):
    """
    Price directive.
    """

    amount: AmountValue
    currency: str
    date: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["price"]


class DirectiveJson11(BaseModel):
    """
    Query directive.
    """

    date: str
    meta: dict[str, MetaValueJson] | None = None
    name: str
    query_string: str
    type: Literal["query"]


class DirectiveJson12(BaseModel):
    """
    Custom directive.

    `values` carries the positional arguments after the type
    keyword. Each value is a [`TypedValueJson`] tagged union
    (`{type, value}`) that preserves the host `MetaValue`
    variant tag, so JS consumers can distinguish (for example)
    a `Date` from a `String` from an `Account` — all of which
    would otherwise collapse to bare JSON strings under the
    untagged `MetaValueJson` shape.

    Pre-#1168: `values` was dropped entirely from the JSON output.
    Pre-#1207: present but emitted raw via `MetaValueJson` (lossy).
    Post-#1207: emitted via `TypedValueJson` (this variant), mirroring
    FFI-WASI's `Vec<TypedValue>`.

    Both `values` and `meta` use `skip_serializing_if` to omit
    the field when empty (consistent shape: a Custom directive
    with no positional args and no metadata serializes as
    `{type, date, custom_type}`, matching what the TS shape
    declares via `values?` / `meta?`).
    """

    custom_type: str
    date: str
    meta: dict[str, MetaValueJson] | None = None
    type: Literal["custom"]
    values: list[TypedValueJson] | None = Field(
        None,
        description="Positional values after the `custom TYPE` keyword. Each\nentry is a [`TypedValueJson`] (`{type, value}`) — the\ntagged shape preserves the host `MetaValue` variant tag so\nJS consumers can distinguish a `Date` from a `String` from\nan `Account` (closes #1207). Mirrors FFI-WASI's\n`Vec<TypedValue>` exactly.",
    )


class DirectiveJson(
    RootModel[
        DirectiveJson1
        | DirectiveJson2
        | DirectiveJson3
        | DirectiveJson4
        | DirectiveJson5
        | DirectiveJson6
        | DirectiveJson7
        | DirectiveJson8
        | DirectiveJson9
        | DirectiveJson10
        | DirectiveJson11
        | DirectiveJson12
    ]
):
    root: (
        DirectiveJson1
        | DirectiveJson2
        | DirectiveJson3
        | DirectiveJson4
        | DirectiveJson5
        | DirectiveJson6
        | DirectiveJson7
        | DirectiveJson8
        | DirectiveJson9
        | DirectiveJson10
        | DirectiveJson11
        | DirectiveJson12
    ) = Field(
        ...,
        description="A directive in JSON-serializable form.\n\nEach variant corresponds to a Beancount directive type, with fields\nrepresenting the directive's data in a JavaScript-friendly format.\n\nAll variants carry a `meta` field with user-defined key/value\nmetadata from the source (issue #1168). Empty metadata serializes\nas an absent field, so existing consumers continue to see the\npre-#1168 shape on directives without explicit metadata.",
    )


class EditorDocumentSymbol(BaseModel):
    """
    A document symbol for the outline view.
    """

    children: list[EditorDocumentSymbol] | None = Field(
        None, description="Children of this symbol (e.g., postings in a transaction)."
    )
    deprecated: bool | None = Field(
        None, description="Whether this symbol is deprecated (e.g., closed account)."
    )
    detail: str | None = Field(None, description="More detail for this symbol.")
    kind: SymbolKind = Field(..., description="The kind of this symbol.")
    name: str = Field(..., description="The name of this symbol.")
    range: EditorRange = Field(..., description="The range enclosing this symbol.")


class EditorHoverInfo(BaseModel):
    """
    Hover information for a symbol.
    """

    contents: str = Field(..., description="The hover content (Markdown formatted).")
    range: EditorRange | None = Field(
        None, description="The range of the hovered symbol (optional)."
    )


class EditorReference(BaseModel):
    """
    A reference to a symbol in the document.
    """

    context: str | None = Field(
        None, description="Human-readable context (e.g., directive type)."
    )
    is_definition: bool = Field(
        ..., description="Whether this is the defining occurrence."
    )
    kind: ReferenceKind = Field(..., description="The kind of reference.")
    range: EditorRange = Field(..., description="The range of this reference.")


class EditorReferencesResult(BaseModel):
    """
    Result of a find-references request.
    """

    kind: ReferenceKind = Field(..., description="The kind of symbol.")
    references: list[EditorReference] = Field(..., description="All references found.")
    symbol: str = Field(..., description="The symbol being searched for.")


class FormatResult(BaseModel):
    """
    Result of formatting.
    """

    errors: list[BeancountError] = Field(..., description="Format errors.")
    formatted: str | None = Field(
        ...,
        description="Formatted source (if successful). Emitted as JSON `null` on\nfailure; no `skip_serializing_if`, so the field is always\npresent on the wire.",
    )


class LedgerJson(BaseModel):
    """
    A parsed Beancount ledger.

    **Renamed to `LedgerJson` on the TS side** to avoid colliding with
    the wasm-bindgen-exported `Ledger` class (the runtime wrapper that
    owns the parsed data). `LedgerJson` is the wire shape; `Ledger` is
    the class consumers instantiate via `Ledger.fromFiles(...)`. The
    Rust struct keeps the shorter name for internal use; the rename
    is applied via `#[ts(rename = ...)]`.
    """

    directives: list[DirectiveJson] = Field(
        ..., description="All directives in the ledger."
    )
    options: LedgerOptions = Field(..., description="Ledger options.")


class PadResult(BaseModel):
    """
    Result of pad expansion.
    """

    directives: list[DirectiveJson] = Field(
        ...,
        description="The original directives, verbatim. `Pad` directives are NOT\nremoved — consumers wanting a pads-removed view should\nfilter on directive type. The `padding_transactions` field\ncarries the synthesized P-flag transactions separately.",
    )
    errors: list[BeancountError] = Field(
        ...,
        description="Pad processing errors (e.g. unused pads with no matching\nbalance assertion).",
    )
    padding_transactions: list[DirectiveJson] = Field(
        ...,
        description="Generated padding transactions (synthesized P-flag, one per\npad-balance pair, multi-currency pads produce one per\ncurrency).",
    )


class ParseResult(BaseModel):
    """
    Result of parsing a Beancount file.
    """

    errors: list[BeancountError] = Field(..., description="Parse errors.")
    ledger: LedgerJson | None = Field(
        ...,
        description='The parsed ledger (if successful). Emitted as JSON `null` when\nparsing failed entirely; no `skip_serializing_if`, so the field\nis always present on the wire (TS: `Ledger | null`, not\n`ledger?`). See the `#[schemars(extend(...))]` on the struct\nitself for the "required-and-nullable" wire-contract enforcement.',
    )


class PluginResult(BaseModel):
    """
    Result of running a plugin.
    """

    directives: list[DirectiveJson] = Field(..., description="Modified directives.")
    errors: list[BeancountError] = Field(..., description="Plugin errors/warnings.")


class QueryResult(BaseModel):
    """
    Result of a BQL query.
    """

    columns: list[str] = Field(..., description="Column names.")
    errors: list[BeancountError] = Field(..., description="Query errors.")
    rows: list[list[CellValue]] = Field(..., description="Result rows.")


class ValidationResult(BaseModel):
    """
    Result of validation.
    """

    errors: list[BeancountError] = Field(..., description="Validation errors.")
    valid: bool = Field(..., description="Whether the ledger is valid.")


CellValue.model_rebuild()
EditorDocumentSymbol.model_rebuild()
