"""Fill primitives for unified OOXML styling.

Provides solid, gradient, and pattern fill definitions for shapes,
cells, backgrounds, and other elements.
"""

from __future__ import annotations

from dataclasses import dataclass
from enum import Enum
from typing import Dict, List, Optional

from tokenmoulds.ir.colors import ColorRef


__all__ = [
    "GradientStop",
    "GradientType",
    "PathGradientShape",
    "FillToRect",
    "GradientFill",
    "FillType",
    "Fill",
]


# =============================================================================
# FILL PRIMITIVES
# =============================================================================


@dataclass
class GradientStop:
    """A single stop in a gradient fill.

    Position is in OOXML percentage units (0-100000).
    """

    position: int  # 0-100000 (0 = start, 100000 = end)
    color: ColorRef


class GradientType(Enum):
    """Gradient direction/type."""

    LINEAR = "lin"
    PATH = "path"  # Radial/path-based


class PathGradientShape(Enum):
    """Shape of path gradient."""

    CIRCLE = "circle"
    RECT = "rect"
    SHAPE = "shape"  # Follow shape outline


@dataclass
class FillToRect:
    """Defines the focus rectangle for path gradients.

    This controls WHERE the gradient center is positioned.
    Values are in OOXML percentage units (0-100000).

    For an off-center radial gradient:
    - l=50000, t=-80000, r=50000, b=180000
    Creates a gradient with center at (50%, -80%) extending to (50%, 180%)

    The gradient interpolates from the center point outward to the edges
    of this rectangle.

    Examples:
        >>> # Centered radial (default behavior)
        >>> FillToRect(l=50000, t=50000, r=50000, b=50000)

        >>> # Top-left corner glow
        >>> FillToRect(l=0, t=0, r=100000, b=100000)

        >>> # Off-center dramatic lighting
        >>> FillToRect(l=50000, t=-80000, r=50000, b=180000)
    """

    l: int = 50000  # Left edge percentage
    t: int = 50000  # Top edge percentage
    r: int = 50000  # Right edge percentage
    b: int = 50000  # Bottom edge percentage

    def to_dict(self) -> Dict[str, int]:
        """Convert to dict for XML emission."""
        return {"l": self.l, "t": self.t, "r": self.r, "b": self.b}


@dataclass
class GradientFill:
    """Gradient fill definition.

    Supports:
    - Linear gradients at any angle (not just 0/90/180/270)
    - Path/radial gradients with off-center focus points
    - Theme colors with modifier stacking

    Examples:
        >>> # Linear gradient at 45° (hidden from GUI!)
        >>> GradientFill.linear(
        ...     stops=[
        ...         GradientStop.at_percent(0, ColorRef.theme(ThemeColor.ACCENT1, tint=50)),
        ...         GradientStop.at_percent(100, ColorRef.theme(ThemeColor.ACCENT1, shade=50)),
        ...     ],
        ...     angle=45,
        ... )

        >>> # Radial gradient with off-center focus (dramatic lighting effect)
        >>> GradientFill.radial(
        ...     stops=[...],
        ...     focus=FillToRect.offset(50, -80),  # Light from above
        ... )
    """

    stops: List[GradientStop]
    gradient_type: GradientType = GradientType.LINEAR
    angle: float = 0  # Degrees (any value 0-360, not just presets!)
    rotate_with_shape: bool = True
    # For path gradients
    path_shape: Optional[PathGradientShape] = None
    fill_to_rect: Optional[FillToRect] = None

    @classmethod
    def linear(
        cls,
        stops: List[GradientStop],
        angle: float = 0,
        rotate_with_shape: bool = True,
    ) -> GradientFill:
        """Create a linear gradient at any angle.

        Args:
            stops: Gradient color stops
            angle: Angle in degrees (0=left-to-right, 90=top-to-bottom)
            rotate_with_shape: Whether gradient rotates with shape
        """
        return cls(
            stops=stops,
            gradient_type=GradientType.LINEAR,
            angle=angle,
            rotate_with_shape=rotate_with_shape,
        )

    @classmethod
    def radial(
        cls,
        stops: List[GradientStop],
        focus: Optional[FillToRect] = None,
        shape: PathGradientShape = PathGradientShape.CIRCLE,
    ) -> GradientFill:
        """Create a radial/path gradient.

        Args:
            stops: Gradient color stops (0 = center, 100 = edge)
            focus: Focus rectangle for off-center effects
            shape: Shape of the gradient (circle, rect, shape)
        """
        return cls(
            stops=stops,
            gradient_type=GradientType.PATH,
            path_shape=shape,
            fill_to_rect=focus or FillToRect(l=50000, t=50000, r=50000, b=50000),
        )


class FillType(Enum):
    """Type of fill."""

    NONE = "none"
    SOLID = "solid"
    GRADIENT = "gradient"
    PATTERN = "pattern"


@dataclass
class Fill:
    """A fill definition for shapes, cells, backgrounds, etc.

    Examples:
        >>> # No fill (transparent)
        >>> Fill.none()

        >>> # Solid accent color
        >>> Fill.solid(ColorRef.theme(ThemeColor.ACCENT1))

        >>> # Solid color with 50% tint
        >>> Fill.solid(ColorRef.theme(ThemeColor.ACCENT1, tint=50))

        >>> # Solid color with 30% opacity
        >>> Fill.solid(ColorRef.rgb("#000000", alpha=30))
    """

    fill_type: FillType = FillType.NONE
    color: Optional[ColorRef] = None
    gradient_fill: Optional[GradientFill] = None
    # Pattern fill (not commonly used)
    pattern_type: Optional[str] = None
    pattern_fg: Optional[ColorRef] = None
    pattern_bg: Optional[ColorRef] = None

    @classmethod
    def none(cls) -> Fill:
        """Create a no-fill (transparent)."""
        return cls(fill_type=FillType.NONE)

    @classmethod
    def solid(cls, color: ColorRef) -> Fill:
        """Create a solid color fill."""
        return cls(fill_type=FillType.SOLID, color=color)

    @classmethod
    def gradient(cls, gradient: GradientFill) -> Fill:
        """Create a gradient fill."""
        return cls(fill_type=FillType.GRADIENT, gradient_fill=gradient)
