"""Custom geometry primitives for OOXML shapes.

Provides path commands, points, arcs, and custom geometry definitions
for creating vector shapes beyond the ~200 preset shapes.
"""

from __future__ import annotations

from dataclasses import dataclass, field
from enum import Enum
from typing import Dict, List, Literal, Optional, Union


__all__ = [
    "PathCommand",
    "PathPoint",
    "ArcParams",
    "PathSegment",
    "GeometryPath",
    "CustomGeometry",
]


# =============================================================================
# CUSTOM GEOMETRY PRIMITIVES (for custGeom shapes)
# =============================================================================


class PathCommand(Enum):
    """Path command types for custom geometry."""

    MOVE_TO = "moveTo"
    LINE_TO = "lnTo"
    ARC_TO = "arcTo"
    QUAD_BEZIER_TO = "quadBezTo"
    CUBIC_BEZIER_TO = "cubicBezTo"
    CLOSE = "close"


@dataclass
class PathPoint:
    """A point in custom geometry path.

    Coordinates in EMU or as formulas referencing shape dimensions.
    """

    x: Union[int, str]  # EMU or formula like "w/2"
    y: Union[int, str]  # EMU or formula like "h/2"


@dataclass
class ArcParams:
    """Arc parameters for arcTo command.

    All angles in 60000ths of a degree.
    """

    width_radius: Union[int, str]  # Half-width of arc ellipse
    height_radius: Union[int, str]  # Half-height of arc ellipse
    start_angle: int  # Start angle (60000ths of degree)
    sweep_angle: int  # Sweep angle (60000ths of degree)


@dataclass
class PathSegment:
    """A segment in a custom geometry path.

    Each segment is a command with associated points/parameters.
    """

    command: PathCommand
    points: List[PathPoint] = field(default_factory=list)
    arc_params: Optional[ArcParams] = None


@dataclass
class GeometryPath:
    """A single path in custom geometry.

    A shape can have multiple paths (compound shapes).
    """

    segments: List[PathSegment]
    fill_mode: Literal[
        "none", "norm", "lighten", "lightenLess", "darken", "darkenLess"
    ] = "norm"
    stroke: bool = True


@dataclass
class CustomGeometry:
    """Custom geometry definition for shapes.

    This is the hidden power feature for shapes - allows any vector path,
    not just the ~200 preset shapes in the GUI.

    Paths use a coordinate system where:
    - w = shape width
    - h = shape height
    - Coordinates can be formulas like "w/2", "h*3/4"

    Example (rounded rectangle with custom corner radius):
        >>> CustomGeometry(
        ...     paths=[GeometryPath(
        ...         segments=[
        ...             PathSegment(PathCommand.MOVE_TO, [PathPoint("r", 0)]),
        ...             PathSegment(PathCommand.LINE_TO, [PathPoint("w-r", 0)]),
        ...             PathSegment(PathCommand.ARC_TO, arc_params=ArcParams("r", "r", -90*60000, 90*60000)),
        ...             # ... more segments
        ...         ]
        ...     )],
        ...     adjust_values={"r": 50000},  # Corner radius as % of min(w,h)
        ... )
    """

    paths: List[GeometryPath]
    # Adjustment handles - values that can be modified by user dragging handles
    adjust_values: Dict[str, int] = field(default_factory=dict)
    # Guide formulas for computing derived values
    guides: Dict[str, str] = field(default_factory=dict)

    @classmethod
    def rectangle(cls) -> CustomGeometry:
        """Simple rectangle (equivalent to preset)."""
        return cls(
            paths=[
                GeometryPath(
                    segments=[
                        PathSegment(PathCommand.MOVE_TO, [PathPoint(0, 0)]),
                        PathSegment(PathCommand.LINE_TO, [PathPoint("w", 0)]),
                        PathSegment(PathCommand.LINE_TO, [PathPoint("w", "h")]),
                        PathSegment(PathCommand.LINE_TO, [PathPoint(0, "h")]),
                        PathSegment(PathCommand.CLOSE),
                    ]
                )
            ]
        )
