"""Pydantic models for the form graph structure."""

from enum import Enum
from typing import Annotated, Any, Literal

from pydantic import BaseModel, ConfigDict, Field

from ..crawling.models import FieldType


class ConditionalOperator(str, Enum):
    EQUALS = "equals"
    NOT_EQUALS = "not_equals"
    EXISTS = "exists"
    NOT_EXISTS = "not_exists"
    CONTAINS = "contains"


class ConditionalEffect(str, Enum):
    SHOW = "show"
    HIDE = "hide"


# --- ValueRange discriminated union ---


class TextValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["text"] = "text"
    min_length: int
    max_length: int
    pattern: str | None
    example_values: list[str]


class NumericValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["numeric"] = "numeric"
    min_value: float
    max_value: float


class OptionItem(BaseModel):
    model_config = ConfigDict(extra="forbid")

    value: str
    label: str
    selector: str | None = None


class DropdownValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["dropdown"] = "dropdown"
    options: list[OptionItem]


class RadioValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["radio"] = "radio"
    options: list[OptionItem]


class CheckboxValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["checkbox"] = "checkbox"
    checked: bool
    unchecked: bool


class DateValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["date"] = "date"
    min_date: str
    max_date: str
    date_format: str


class SliderValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["slider"] = "slider"
    min_value: float
    max_value: float
    step: float


class ComboboxValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["combobox"] = "combobox"
    options: list[OptionItem]


class ClickSelectValueRange(BaseModel):
    model_config = ConfigDict(extra="forbid")

    range_type: Literal["click_select"] = "click_select"
    options: list[OptionItem]


ValueRange = Annotated[
    TextValueRange
    | NumericValueRange
    | DropdownValueRange
    | RadioValueRange
    | CheckboxValueRange
    | DateValueRange
    | SliderValueRange
    | ComboboxValueRange
    | ClickSelectValueRange,
    Field(discriminator="range_type"),
]


# --- Graph node models ---


class ConditionalRule(BaseModel):
    model_config = ConfigDict(extra="forbid")

    rule_id: str
    trigger_field_id: str
    trigger_value: str
    operator: ConditionalOperator
    affected_field_ids: list[str]
    effect: ConditionalEffect
    verified: bool


class FieldNode(BaseModel):
    model_config = ConfigDict(extra="forbid")

    field_id: str
    selector: str
    field_type: FieldType
    label: str
    is_required: bool
    value_range: ValueRange | None = None
    default_value: Any | None = None
    data_key: str
    visibility_condition: str | None = None
    iframe_selector: str | None = None


class PageNode(BaseModel):
    model_config = ConfigDict(extra="forbid")

    page_id: str
    name: str
    wait_for_selector: str
    fields: list[FieldNode]
    next_action_selector: str | None = None
    conditionals: list[ConditionalRule]


class GraphMetadata(BaseModel):
    model_config = ConfigDict(extra="forbid")

    timestamp: str
    version: str
    notes: str


class FormGraph(BaseModel):
    model_config = ConfigDict(extra="forbid")

    url: str
    name: str
    pages: list[PageNode]
    metadata: GraphMetadata
