from __future__ import annotations

from dataclasses import dataclass, field as dc_field

from flow_xhs.cli.spec.enums import (
    CommandStatus,
    ConstraintSeverity,
    ConstraintType,
    DefaultKind,
    ExampleCategory,
    InputSourceKind,
    ParameterGroup,
    ParameterKind,
    ParameterScope,
    ParameterVisibility,
    RequirednessMode,
    ValueKind,
)


@dataclass(frozen=True)
class ConditionExpr:
    op: str
    field: str | None = None
    value: object | None = None
    children: tuple["ConditionExpr", ...] = dc_field(default_factory=tuple)


@dataclass(frozen=True)
class RequirednessSpec:
    mode: RequirednessMode
    message: str | None = None
    condition: ConditionExpr | None = None


@dataclass(frozen=True)
class DefaultSpec:
    kind: DefaultKind
    value: object | None = None
    display_value: str | None = None
    note: str | None = None


@dataclass(frozen=True)
class ValueTypeSpec:
    kind: ValueKind
    item_kind: ValueKind | None = None
    format: str | None = None
    min: int | float | None = None
    max: int | float | None = None
    min_length: int | None = None
    max_length: int | None = None
    pattern: str | None = None
    separator: str | None = None
    nullable: bool = False


@dataclass(frozen=True)
class AllowedValueSpec:
    value: str
    label: str | None = None
    aliases: tuple[str, ...] = dc_field(default_factory=tuple)
    deprecated_aliases: tuple[str, ...] = dc_field(default_factory=tuple)
    description: str | None = None
    hidden: bool = False


@dataclass(frozen=True)
class InputSourceBinding:
    source: InputSourceKind
    priority: int
    required: bool = False
    field_name: str | None = None
    note: str | None = None


@dataclass(frozen=True)
class ParameterSpec:
    id: str
    name: str
    cli_names: tuple[str, ...]
    scope: ParameterScope
    kind: ParameterKind
    group: ParameterGroup
    summary: str
    description: str | None
    value_type: ValueTypeSpec
    requiredness: RequirednessSpec
    default: DefaultSpec | None = None
    allowed_values: tuple[AllowedValueSpec, ...] = dc_field(default_factory=tuple)
    input_bindings: tuple[InputSourceBinding, ...] = dc_field(default_factory=tuple)
    examples: tuple[str, ...] = dc_field(default_factory=tuple)
    visibility: ParameterVisibility = ParameterVisibility.DEFAULT
    deprecated: bool = False
    metadata: dict[str, object] = dc_field(default_factory=dict)


@dataclass(frozen=True)
class ConstraintSpec:
    id: str
    type: ConstraintType
    severity: ConstraintSeverity
    targets: tuple[str, ...]
    message: str
    help_text: str | None = None
    condition: ConditionExpr | None = None
    metadata: dict[str, object] = dc_field(default_factory=dict)


@dataclass(frozen=True)
class EventTypeSpec:
    name: str
    summary: str
    payload_fields: tuple[str, ...] = dc_field(default_factory=tuple)


@dataclass(frozen=True)
class EventSpec:
    type_field: str
    events: tuple[EventTypeSpec, ...] = dc_field(default_factory=tuple)


@dataclass(frozen=True)
class OutputSpec:
    success_command: str
    success_schema_ref: str
    error_schema_ref: str
    data_shape_summary: str
    supports_events: bool = False
    event_channel: str | None = None
    event_spec: EventSpec | None = None


@dataclass(frozen=True)
class ExampleSpec:
    id: str
    title: str
    category: ExampleCategory
    command: str
    description: str | None = None
    machine_friendly: bool = False


@dataclass(frozen=True)
class CommandHelpSpec:
    usage_options_label: str = "COMMAND_OPTIONS"
    usage_options_token: str | None = None
    section_order: tuple[str, ...] = (
        "usage",
        "summary",
        "options",
        "examples",
    )


@dataclass(frozen=True)
class DocTopicSpec:
    id: str
    title: str
    summary: str
    content_markdown: str


@dataclass(frozen=True)
class CommandSpec:
    id: str
    path: tuple[str, ...]
    display_path: str
    summary: str
    description: str | None
    status: CommandStatus
    parameters: tuple[ParameterSpec, ...] = dc_field(default_factory=tuple)
    constraints: tuple[ConstraintSpec, ...] = dc_field(default_factory=tuple)
    examples: tuple[ExampleSpec, ...] = dc_field(default_factory=tuple)
    output: OutputSpec | None = None
    related_commands: tuple[str, ...] = dc_field(default_factory=tuple)
    tags: tuple[str, ...] = dc_field(default_factory=tuple)
    help: CommandHelpSpec | None = None
    metadata: dict[str, object] = dc_field(default_factory=dict)


@dataclass(frozen=True)
class CliSpec:
    spec_version: str
    cli_version: str
    cli_name: str
    product_name: str | None
    summary: str
    description: str | None
    canonical_syntax: str
    global_options: tuple[ParameterSpec, ...] = dc_field(default_factory=tuple)
    commands: tuple[CommandSpec, ...] = dc_field(default_factory=tuple)
    topics: tuple[DocTopicSpec, ...] = dc_field(default_factory=tuple)
    metadata: dict[str, object] = dc_field(default_factory=dict)
