"""
Data models for nono data structures.

These models correspond to the Rust structs defined in src/state.rs and src/v1_routes/.
They support both snake_case and kebab-case field names for compatibility.
"""

from datetime import datetime
from typing import Any, Literal, Optional, Union
from static_refl.options import refl_options, refl_rename
from dataclasses import dataclass, field


# ============================================================================
# Core Data Models (from state.rs)
# ============================================================================

type YieldType = Literal["fail", "report", "ask-human"]


@refl_options(rename_all="kebab-case", tag="func_type")
@dataclass
class ScriptFunc:
    """Script function type."""

    exe: str
    args: list[str]
    func_type: Literal["script"] = "script"


@refl_options(rename_all="kebab-case", tag="func_type")
@dataclass
class HttpFunc:
    """HTTP function type."""

    url: str
    data: Optional[Any] = None
    func_type: Literal["http"] = "http"


# Union type for Func
type Func = ScriptFunc | HttpFunc


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationPushValue:
    """Push value operation."""

    value: Any
    op_kind: Literal["push-value"] = "push-value"


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationPopValue:
    """Pop value operation."""

    op_kind: Literal["pop-value"] = "pop-value"


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationPushHandler:
    """Push handler operation."""

    handler: Union[ScriptFunc, HttpFunc]
    op_kind: Literal["push-handler"] = "push-handler"


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationPopHandler:
    """Pop handler operation."""

    op_kind: Literal["pop-handler"] = "pop-handler"


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationCall:
    """Call operation."""

    func: Union[ScriptFunc, HttpFunc]
    op_kind: Literal["call"] = 'call'


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationResume:
    """Resume operation."""

    data: Any
    op_kind: Literal["resume"] = 'resume'


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationYield:
    """Yield operation."""
    yield_type: YieldType
    data: Any
    op_kind: Literal["yield"] = 'yield'


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationRethrow:
    """Rethrow operation."""
    op_kind: Literal["rethrow"] = "rethrow"


@refl_options(rename_all="kebab-case", tag="op_kind")
@dataclass
class OperationClearCurrentRaise:
    """Clear current raise operation."""
    op_kind: Literal["clear-current-raise"] = "clear-current-raise"


# Union type for Operation
Operation = Union[
    OperationPushValue,
    OperationPopValue,
    OperationPushHandler,
    OperationPopHandler,
    OperationCall,
    OperationResume,
    OperationYield,
    OperationRethrow,
    OperationClearCurrentRaise,
]


@refl_options(rename_all="kebab-case")
@dataclass
class CallingFrame:
    """Calling frame with stacks."""

    calling_entity_id: str
    data: Any
    value_stack: list[Any]
    op_stack: list[Operation]
    handler_stack: list[Any]


@refl_options(rename_all="kebab-case")
@dataclass
class ContinuationTail:
    """Continuation tail for yield/resume."""

    tail_frames: list[CallingFrame]
    yield_type: str
    yield_data: Any


@refl_options(rename_all="kebab-case")
@refl_rename(raise_ = "raise")
@dataclass
class SessionState:
    """Session state."""

    uuid: str
    name: str
    data: Any
    frames: list[CallingFrame]
    raise_: list[ContinuationTail]
    created_at: datetime
    modified_at: datetime


# ============================================================================
# API Request/Response Models
# ============================================================================


# Config endpoints
@refl_options(rename_all="kebab-case")
@dataclass
class ConfigReadResponse:
    """Response from /v1/config/read."""

    config: Any


# Entity endpoints
@refl_options(rename_all="kebab-case")
@dataclass
class EntityReadRequest:
    """Request for /v1/entity/read."""

    id: str


@refl_options(rename_all="kebab-case")
@dataclass
class EntityReadResponse:
    """Response from /v1/entity/read."""

    entity: Optional[Any]


@refl_options(rename_all="kebab-case")
@dataclass
class EntityWriteRequest:
    """Request for /v1/entity/write."""

    id: str
    entity: Any


@refl_options(rename_all="kebab-case")
@dataclass
class EntityWriteResponse:
    """Response from /v1/entity/write."""

    success: bool


# Session endpoints
@refl_options(rename_all="kebab-case")
@dataclass
class SessionCreateRequest:
    """Request for /v1/session/create."""

    name: str
    data: Any
    frame: CallingFrame


@refl_options(rename_all="kebab-case")
@dataclass
class SessionCreateResponse:
    """Response from /v1/session/create."""

    session_id: str


@refl_options(rename_all="kebab-case")
@dataclass
class SessionDeleteRequest:
    """Request for /v1/session/delete."""

    session_id: str


@refl_options(rename_all="kebab-case")
@dataclass
class SessionDeleteResponse:
    """Response from /v1/session/delete."""

    success: bool


@refl_options(rename_all="kebab-case")
@dataclass
class SessionNextRequest:
    """Request for /v1/session/next."""

    session_id: str


@refl_options(rename_all="kebab-case")
@dataclass
class SessionNextResponse:
    """Response from /v1/session/next."""

    success: bool


@refl_options(rename_all="kebab-case")
@dataclass
class SessionGetDataRequest:
    """Request for /v1/session/get-data."""

    session_id: str


@refl_options(rename_all="kebab-case")
@dataclass
class SessionGetDataResponse:
    """Response from /v1/session/get-data."""

    data: Optional[Any]


# Frame endpoints
@refl_options(rename_all="kebab-case")
@dataclass
class FramePushValueRequest:
    """Request for /v1/frame/push-value."""

    session_id: str
    value: Any


@refl_options(rename_all="kebab-case")
@dataclass
class FramePushValueResponse:
    """Response from /v1/frame/push-value."""

    success: bool


@refl_options(rename_all="kebab-case")
@dataclass
class FramePushOpRequest:
    """Request for /v1/frame/push-op."""

    session_id: str
    value: Any
    op: Operation  # Operation union type


@refl_options(rename_all="kebab-case")
@dataclass
class FramePushOpResponse:
    """Response from /v1/frame/push-op."""

    success: bool


@refl_options(rename_all="kebab-case")
@dataclass
class FrameReadDataRequest:
    """Request for /v1/frame/read-data."""

    session_id: str


@refl_options(rename_all="kebab-case")
@dataclass
class FrameReadDataResponse:
    """Response from /v1/frame/read-data."""

    data: Optional[Any]


@refl_options(rename_all="kebab-case")
@dataclass
class FrameWriteDataRequest:
    """Request for /v1/frame/write-data."""

    session_id: str
    data: Any


@refl_options(rename_all="kebab-case")
@dataclass
class FrameWriteDataResponse:
    """Response from /v1/frame/write-data."""

    success: bool
