"""
ODS Models - Layer Types
ODS script layer definitions.
Python equivalent of @optikka/ods-models layer.ts
"""

from typing import Any, Dict, List, Literal, Optional, Union
from pydantic import BaseModel
from ods_models.canvas_globals import CanvasGuides


LayerType = Literal["text", "asset", "shape", "data", "zone", "group", "array"]


class VerbDef(BaseModel):
    """Verb definition as authored in ODS script JSON"""
    use: str
    args: Optional[Dict[str, Any]] = None


LayerBlendMode = Literal[
    "normal", "multiply", "screen", "overlay",
    "darken", "lighten", "color-dodge", "color-burn",
    "hard-light", "soft-light", "difference", "exclusion",
    "hue", "saturation", "color", "luminosity",
]

LayerCompositeOp = Literal[
    "source-over", "source-in", "source-out", "source-atop",
    "destination-over", "destination-in", "destination-out", "destination-atop",
    "lighter", "copy", "xor",
]


class LayerShadow(BaseModel):
    """Shadow params matching IDrawContext.setShadow()"""
    offsetX: float
    offsetY: float
    blur: float
    color: str


class LayerColorOverlay(BaseModel):
    """Color overlay matching IDrawContext.setColorFilter()"""
    color: str
    blendMode: LayerBlendMode


class LayerGradientStop(BaseModel):
    """Gradient stop matching IDrawContext.fillGradient()"""
    offset: float   # 0-1
    color: str       # CSS color


class LayerGradient(BaseModel):
    """Gradient definition matching IDrawContext.fillGradient()"""
    type: Literal["linear", "radial"]
    angle: Optional[float] = None
    stops: List[LayerGradientStop]
    cx: Optional[float] = None
    cy: Optional[float] = None
    r: Optional[float] = None


class LayerRender(BaseModel):
    """Full render options for a layer — typed to match IDrawContext capabilities"""
    # Implemented
    opacity: Optional[float] = None
    rotation: Optional[float] = None
    objectFit: Optional[Literal["contain", "cover", "fill", "fitWidth", "fitHeight"]] = None
    objectPosition: Optional[Dict[str, Any]] = None
    trimTransparent: Optional[bool] = None
    # Compositing (stubbed in IDrawContext)
    blendMode: Optional[LayerBlendMode] = None
    compositeOp: Optional[LayerCompositeOp] = None
    # Fill (stubbed in IDrawContext)
    fill: Optional[str] = None
    gradient: Optional[LayerGradient] = None
    # Effects (stubbed in IDrawContext)
    shadow: Optional[LayerShadow] = None
    blur: Optional[float] = None
    # Color manipulation (stubbed in IDrawContext)
    colorOverlay: Optional[LayerColorOverlay] = None
    colorMatrix: Optional[List[float]] = None  # 4x5 = 20 floats


class BreakpointCase(BaseModel):
    """
    Conditional verb chain for responsive layouts.
    when entries are CanvasAspect values or flex preset IDs.
    """
    when: List[str]
    verbs: List[VerbDef]
    render: Optional[LayerRender] = None


class BaseLayer(BaseModel):
    """Base layer definition shared by all layer types"""
    id: str
    name: str
    slot_key: str
    type: LayerType
    x: float
    y: float
    width: float
    height: float
    tx: Optional[float] = None
    ty: Optional[float] = None
    visible: Optional[bool] = None
    opacity: Optional[float] = None
    zIndex: Optional[int] = None
    render: Optional[LayerRender] = None
    verbs: Optional[List[VerbDef]] = None
    cases: Optional[List[BreakpointCase]] = None
    guides: Optional[List[CanvasGuides]] = None


class TextLayer(BaseLayer):
    type: Literal["text"] = "text"


class AssetLayer(BaseLayer):
    type: Literal["asset"] = "asset"
    src: Optional[str] = None


class ShapeLayer(BaseLayer):
    type: Literal["shape"] = "shape"
    shapeKind: Literal["rect", "ellipse"]
    fill: Optional[str] = None
    stroke: Optional[str] = None


class DataLayer(BaseLayer):
    type: Literal["data"] = "data"


class ZoneLayer(BaseLayer):
    type: Literal["zone"] = "zone"


class GroupLayer(BaseLayer):
    type: Literal["group"] = "group"
    members: Optional[List[str]] = None


class ArrayLayer(BaseLayer):
    type: Literal["array"] = "array"


Layer = Union[TextLayer, AssetLayer, ShapeLayer, DataLayer, ZoneLayer, GroupLayer, ArrayLayer]
