"""
Component Behavior Schema - Full React → SST Extraction System.

This module defines Pydantic models for extracting ALL behavioral patterns
from React components into a declarative SST format that can be:
  1. Stored in database (Django JSONField)
  2. Configured via CMS
  3. Generated into TypeScript
  4. Validated at runtime

Extraction Categories:
    1. State Schema - Component state shape and initial values
    2. Actions - Event handlers and their signatures
    3. Computed State - Derived values and transformations
    4. Transitions - CSS transitions and animations
    5. Breakpoints - Responsive behavior definitions
    6. Accessibility - ARIA attributes and keyboard navigation
    7. Keyboard Shortcuts - Hotkey bindings
    8. View Options - Configurable options with labels

This is the CORE of LightWave's component-as-data architecture.
Django becomes the configuration backend; React becomes the rendering engine.

AUTO-GENERATED - regenerate with: lw ui extract-behavior
"""

from enum import Enum
from typing import Any

from pydantic import Field

from lightwave.schema.pydantic.core.base import JSONFieldSchema

# =============================================================================
# STATE SCHEMA - Component State Definitions
# =============================================================================


class StateType(str, Enum):
    """Primitive state types that map to TypeScript/Python."""

    STRING = "string"
    NUMBER = "number"
    BOOLEAN = "boolean"
    DATE = "date"
    DATETIME = "datetime"
    ARRAY = "array"
    OBJECT = "object"
    ENUM = "enum"
    NULLABLE = "nullable"


class StateFieldDefinition(JSONFieldSchema):
    """
    Definition of a single state field.

    Maps to React useState or controlled prop patterns:
        const [page, setPage] = useState(1);
        // → StateFieldDefinition(name="page", type="number", default=1)
    """

    name: str = Field(description="State field name (e.g., 'page', 'selectedDate')")
    state_type: StateType = Field(alias="stateType", description="Primitive type of the state")
    default: Any | None = Field(default=None, description="Default value")
    nullable: bool = Field(default=False, description="Whether state can be null")
    description: str | None = Field(default=None, description="What this state represents")

    # For enum types
    allowed_values: list[str] | None = Field(
        default=None,
        alias="allowedValues",
        description="Valid values for enum types",
    )

    # For array types
    item_type: str | None = Field(
        default=None,
        alias="itemType",
        description="Type of array items",
    )

    # Persistence options
    persist_to: str | None = Field(
        default=None,
        alias="persistTo",
        description="Where to persist: 'url' | 'localStorage' | 'server'",
    )


class ComponentStateSchema(JSONFieldSchema):
    """
    Complete state schema for a component.

    Defines all stateful data a component manages.
    This becomes the source of truth for state management.
    """

    component_name: str = Field(alias="componentName", description="Component this state belongs to")
    fields: list[StateFieldDefinition] = Field(description="All state fields")

    @property
    def field_names(self) -> list[str]:
        """Get list of all state field names."""
        return [f.name for f in self.fields]


# =============================================================================
# ACTIONS - Event Handlers and Mutations
# =============================================================================


class ActionParameterType(str, Enum):
    """Types for action parameters."""

    STRING = "string"
    NUMBER = "number"
    BOOLEAN = "boolean"
    DATE = "date"
    OBJECT = "object"
    VOID = "void"
    EVENT = "event"  # React SyntheticEvent


class ActionParameter(JSONFieldSchema):
    """Parameter definition for an action."""

    name: str = Field(description="Parameter name")
    param_type: ActionParameterType = Field(alias="paramType", description="Parameter type")
    optional: bool = Field(default=False, description="Whether optional")
    description: str | None = Field(default=None, description="What this param is for")


class ActionCategory(str, Enum):
    """Categories of component actions."""

    NAVIGATION = "navigation"  # Page/route changes
    SELECTION = "selection"  # Item/date selection
    MUTATION = "mutation"  # Data changes
    TOGGLE = "toggle"  # Boolean flips
    SUBMIT = "submit"  # Form submissions
    FETCH = "fetch"  # Data fetching
    SIDE_EFFECT = "side_effect"  # External effects


class ActionDefinition(JSONFieldSchema):
    """
    Definition of a component action (event handler).

    Maps to React event handlers:
        onClick={() => onPageChange?.(Math.max(0, page - 1))}
        // → ActionDefinition(name="onPageChange", category="navigation", ...)
    """

    name: str = Field(description="Action name (e.g., 'onPageChange', 'setSelectedDate')")
    category: ActionCategory = Field(description="Action category")
    parameters: list[ActionParameter] = Field(default_factory=list, description="Action parameters")
    return_type: str = Field(
        default="void",
        alias="returnType",
        description="Return type (usually void)",
    )
    description: str | None = Field(default=None, description="What this action does")

    # State mutations
    mutates: list[str] | None = Field(default=None, description="State fields this action mutates")

    # Validation/constraints
    constraints: dict[str, Any] | None = Field(
        default=None,
        description="Constraints (e.g., {'min': 1, 'max': 'total'})",
    )

    # API endpoint (if action triggers server call)
    api_endpoint: str | None = Field(
        default=None,
        alias="apiEndpoint",
        description="API endpoint to call",
    )


# =============================================================================
# COMPUTED STATE - Derived Values
# =============================================================================


class ComputationRule(str, Enum):
    """Types of computation rules."""

    FILTER = "filter"
    MAP = "map"
    REDUCE = "reduce"
    DERIVE = "derive"
    TRANSFORM = "transform"
    MEMOIZE = "memoize"


class ComputedFieldDefinition(JSONFieldSchema):
    """
    Definition of a computed/derived field.

    Maps to useMemo patterns:
        const zonedEvents = useMemo(() => events.map(...), [events]);
        // → ComputedFieldDefinition(name="zonedEvents", rule="map", ...)
    """

    name: str = Field(description="Computed field name")
    rule: ComputationRule = Field(description="How value is computed")
    dependencies: list[str] = Field(description="State/prop fields this depends on")
    result_type: str = Field(alias="resultType", description="Type of computed result")
    description: str | None = Field(default=None, description="What this computes")

    # For filter/map rules
    predicate: str | None = Field(default=None, description="Filter/map predicate expression")

    # For derive rules
    expression: str | None = Field(default=None, description="Derivation expression")


# =============================================================================
# TRANSITIONS & ANIMATIONS
# =============================================================================


class TransitionTiming(str, Enum):
    """CSS timing functions."""

    LINEAR = "linear"
    EASE = "ease"
    EASE_IN = "ease-in"
    EASE_OUT = "ease-out"
    EASE_IN_OUT = "ease-in-out"


class TransitionDefinition(JSONFieldSchema):
    """
    CSS transition definition.

    Maps to Tailwind transition classes:
        "transition duration-100 ease-linear"
        // → TransitionDefinition(duration=100, timing="linear")
    """

    property: str = Field(default="all", description="CSS property to transition")
    duration: int = Field(description="Duration in milliseconds")
    timing: TransitionTiming = Field(default=TransitionTiming.EASE, description="Timing function")
    delay: int = Field(default=0, description="Delay in milliseconds")

    def to_tailwind(self) -> str:
        """Generate Tailwind class string."""
        parts = ["transition"]
        if self.property != "all":
            parts[0] = f"transition-{self.property}"
        parts.append(f"duration-{self.duration}")
        parts.append(f"ease-{self.timing.value}")
        if self.delay > 0:
            parts.append(f"delay-{self.delay}")
        return " ".join(parts)


class AnimationKeyframe(JSONFieldSchema):
    """Keyframe in an animation sequence."""

    offset: float = Field(ge=0, le=1, description="Keyframe offset (0-1)")
    properties: dict[str, str] = Field(description="CSS properties at this keyframe")


class AnimationDefinition(JSONFieldSchema):
    """
    CSS animation definition.

    For more complex animations beyond transitions.
    """

    name: str = Field(description="Animation name")
    duration: int = Field(description="Duration in milliseconds")
    timing: TransitionTiming = Field(default=TransitionTiming.EASE)
    iteration_count: int | str = Field(
        default=1,
        alias="iterationCount",
        description="Number of iterations or 'infinite'",
    )
    keyframes: list[AnimationKeyframe] = Field(description="Animation keyframes")
    trigger: str | None = Field(default=None, description="What triggers this animation")


# =============================================================================
# BREAKPOINTS - Responsive Behavior
# =============================================================================


class Breakpoint(str, Enum):
    """Standard responsive breakpoints (Tailwind)."""

    SM = "sm"  # 640px
    MD = "md"  # 768px
    LG = "lg"  # 1024px
    XL = "xl"  # 1280px
    XXL = "2xl"  # 1536px


class BreakpointBehavior(JSONFieldSchema):
    """
    Behavior that changes at breakpoints.

    Maps to Tailwind responsive prefixes:
        "md:hidden lg:flex"
        // → BreakpointBehavior(breakpoint="md", hidden=True), etc.
    """

    breakpoint: Breakpoint = Field(description="Breakpoint this applies at")
    visible: bool | None = Field(default=None, description="Whether visible at this breakpoint")
    layout: str | None = Field(default=None, description="Layout mode (flex, grid, block)")
    text: str | None = Field(default=None, description="Text to show/hide at breakpoint")
    properties: dict[str, str] | None = Field(default=None, description="Other CSS properties")


class ResponsiveConfig(JSONFieldSchema):
    """
    Complete responsive configuration for a component.

    Defines how component adapts across screen sizes.
    """

    component_name: str = Field(alias="componentName")
    default_visible: bool = Field(
        default=True,
        alias="defaultVisible",
        description="Visibility when no breakpoint matches",
    )
    behaviors: list[BreakpointBehavior] = Field(description="Breakpoint-specific behaviors")


# =============================================================================
# ACCESSIBILITY
# =============================================================================


class AriaAttribute(JSONFieldSchema):
    """ARIA attribute definition."""

    name: str = Field(description="ARIA attribute name (without 'aria-' prefix)")
    value: str | bool = Field(description="Attribute value")
    dynamic: bool = Field(default=False, description="Whether value changes based on state")
    state_binding: str | None = Field(
        default=None,
        alias="stateBinding",
        description="State field this is bound to",
    )


class KeyboardNavigation(JSONFieldSchema):
    """Keyboard navigation configuration."""

    key: str = Field(description="Key or key combo (e.g., 'ArrowLeft', '⌘D')")
    action: str = Field(description="Action to trigger")
    description: str | None = Field(default=None, description="What this shortcut does")
    prevent_default: bool = Field(
        default=True,
        alias="preventDefault",
        description="Whether to prevent default browser behavior",
    )


class AccessibilityConfig(JSONFieldSchema):
    """
    Complete accessibility configuration.

    Defines ARIA attributes and keyboard navigation.
    """

    role: str | None = Field(default=None, description="ARIA role")
    label: str | None = Field(default=None, description="aria-label value")
    label_binding: str | None = Field(
        default=None,
        alias="labelBinding",
        description="State field for dynamic label",
    )
    attributes: list[AriaAttribute] = Field(default_factory=list, description="ARIA attributes")
    keyboard: list[KeyboardNavigation] = Field(default_factory=list, description="Keyboard shortcuts")


# =============================================================================
# VIEW OPTIONS - Configurable Options
# =============================================================================


class ViewOption(JSONFieldSchema):
    """
    Configurable view/mode option.

    Maps to option objects in components:
        { value: "day", label: "Day view", addon: "⌘D" }
    """

    value: str = Field(description="Option value")
    label: str = Field(description="Display label")
    addon: str | None = Field(default=None, description="Addon text (e.g., keyboard shortcut)")
    icon: str | None = Field(default=None, description="Icon component name")
    disabled: bool = Field(default=False, description="Whether option is disabled")


class ViewOptionsConfig(JSONFieldSchema):
    """Configuration for a set of view options."""

    name: str = Field(description="Name of this option set (e.g., 'viewOptions')")
    options: list[ViewOption] = Field(description="Available options")
    default_value: str = Field(alias="defaultValue", description="Default selected value")


# =============================================================================
# UNIFIED COMPONENT BEHAVIOR
# =============================================================================


class ComponentBehavior(JSONFieldSchema):
    """
    Complete behavioral definition for a UI component.

    This is the MASTER schema that combines all extractable patterns.
    This model can be:
        - Stored in Django JSONField
        - Edited via CMS
        - Validated at runtime
        - Generated into TypeScript
    """

    component_name: str = Field(alias="componentName", description="Component name")
    category: str = Field(description="Component category path")
    source_file: str = Field(alias="sourceFile", description="TypeScript source file")

    # State management
    state: ComponentStateSchema | None = Field(default=None, description="Component state schema")

    # Actions/events
    actions: list[ActionDefinition] = Field(default_factory=list, description="Component actions")

    # Computed state
    computed: list[ComputedFieldDefinition] = Field(default_factory=list, description="Computed/derived fields")

    # Transitions & animations
    transitions: list[TransitionDefinition] = Field(default_factory=list, description="CSS transitions")
    animations: list[AnimationDefinition] = Field(default_factory=list, description="CSS animations")

    # Responsive behavior
    responsive: ResponsiveConfig | None = Field(default=None, description="Responsive configuration")

    # Accessibility
    accessibility: AccessibilityConfig | None = Field(default=None, description="Accessibility configuration")

    # View options
    view_options: list[ViewOptionsConfig] = Field(
        default_factory=list,
        alias="viewOptions",
        description="Configurable option sets",
    )

    # Constants
    constants: dict[str, Any] = Field(default_factory=dict, description="Component constants")


# =============================================================================
# EXPORTS
# =============================================================================

__all__ = [
    # State
    "StateType",
    "StateFieldDefinition",
    "ComponentStateSchema",
    # Actions
    "ActionParameterType",
    "ActionParameter",
    "ActionCategory",
    "ActionDefinition",
    # Computed
    "ComputationRule",
    "ComputedFieldDefinition",
    # Transitions
    "TransitionTiming",
    "TransitionDefinition",
    "AnimationKeyframe",
    "AnimationDefinition",
    # Breakpoints
    "Breakpoint",
    "BreakpointBehavior",
    "ResponsiveConfig",
    # Accessibility
    "AriaAttribute",
    "KeyboardNavigation",
    "AccessibilityConfig",
    # View Options
    "ViewOption",
    "ViewOptionsConfig",
    # Unified
    "ComponentBehavior",
]
