"""Stroke/line primitives for unified OOXML styling.

Provides line cap, join, dash pattern, and stroke definitions for
shapes, borders, and other elements.
"""

from __future__ import annotations

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

from tokenmoulds.design.units import EMU_PER_POINT
from tokenmoulds.ir.colors import ColorRef


__all__ = [
    "LineCap",
    "LineJoin",
    "LineCompound",
    "LineDash",
    "DashSegment",
    "CustomDash",
    "LineAlign",
    "Stroke",
]


# =============================================================================
# STROKE/LINE PRIMITIVES
# =============================================================================


class LineCap(Enum):
    """Line end cap style."""

    FLAT = "flat"
    ROUND = "rnd"
    SQUARE = "sq"


class LineJoin(Enum):
    """Line join style."""

    ROUND = "round"
    BEVEL = "bevel"
    MITER = "miter"


class LineCompound(Enum):
    """Compound line style."""

    SINGLE = "sng"
    DOUBLE = "dbl"
    THICK_THIN = "thickThin"
    THIN_THICK = "thinThick"
    TRIPLE = "tri"


class LineDash(Enum):
    """Preset dash patterns."""

    SOLID = "solid"
    DOT = "dot"
    DASH = "dash"
    DASH_DOT = "dashDot"
    LONG_DASH = "lgDash"
    LONG_DASH_DOT = "lgDashDot"
    LONG_DASH_DOT_DOT = "lgDashDotDot"
    SYSTEM_DOT = "sysDot"
    SYSTEM_DASH = "sysDash"
    SYSTEM_DASH_DOT = "sysDashDot"
    SYSTEM_DASH_DOT_DOT = "sysDashDotDot"
    CUSTOM = "custom"  # Use CustomDash for pattern


@dataclass
class DashSegment:
    """A single dash or space segment.

    Values are in OOXML percentage units (100000 = 100%).
    These are relative to line width.
    """

    dash: int  # Length of dash (percentage of line width)
    space: int  # Length of following space

    @classmethod
    def from_ratio(cls, dash: float, space: float) -> DashSegment:
        """Create from simple ratio values.

        Args:
            dash: Dash length as multiple of line width (e.g., 3 = 3x width)
            space: Space length as multiple of line width
        """
        return cls(dash=int(dash * 100000), space=int(space * 100000))


@dataclass
class CustomDash:
    """Custom dash pattern for lines.

    Allows any dash-to-space ratio, not limited to GUI presets.
    The pattern repeats along the line.

    Example:
        >>> # 3:1 dash-to-space ratio (long dashes)
        >>> CustomDash([DashSegment.from_ratio(3, 1)])

        >>> # Morse code pattern: dot-dash
        >>> CustomDash([
        ...     DashSegment.from_ratio(1, 1),  # dot
        ...     DashSegment.from_ratio(3, 1),  # dash
        ... ])

        >>> # Decorative: dash-dot-dot
        >>> CustomDash.morse_pattern([3, 1, 1])  # lengths, equal spacing
    """

    segments: List[DashSegment]

    @classmethod
    def simple(cls, dash: float, space: float) -> CustomDash:
        """Create a simple repeating dash pattern.

        Args:
            dash: Dash length as multiple of line width
            space: Space length as multiple of line width
        """
        return cls([DashSegment.from_ratio(dash, space)])


class LineAlign(Enum):
    """Line alignment relative to shape edge."""

    CENTER = "ctr"
    INSIDE = "in"
    OUTSIDE = "out"


@dataclass
class Stroke:
    """Line/stroke properties for shapes, borders, etc.

    Width is in EMU (English Metric Units):
    - 914400 EMU = 1 inch
    - 12700 EMU = 1 point
    - 9525 EMU = 0.75 pt (common thin line)

    Examples:
        >>> # 1pt solid black line
        >>> Stroke.solid(ColorRef.rgb("#000000"), width_pt=1)

        >>> # 2pt dashed accent color
        >>> Stroke.dashed(ColorRef.theme(ThemeColor.ACCENT1), width_pt=2)

        >>> # Custom dash pattern (3:1 ratio - not in GUI!)
        >>> Stroke.custom_dashed(
        ...     ColorRef.theme(ThemeColor.ACCENT1),
        ...     CustomDash.simple(3, 1),
        ...     width_pt=2,
        ... )

        >>> # No stroke (for shapes without borders)
        >>> Stroke.none()
    """

    width_emu: int = 0  # 0 = no stroke
    color: Optional[ColorRef] = None
    dash: LineDash = LineDash.SOLID
    custom_dash: Optional[CustomDash] = None  # For LineDash.CUSTOM
    cap: LineCap = LineCap.FLAT
    join: LineJoin = LineJoin.ROUND
    compound: LineCompound = LineCompound.SINGLE
    align: LineAlign = LineAlign.CENTER
    miter_limit: Optional[int] = None  # In percentage units (800000 = 8x)

    @classmethod
    def none(cls) -> Stroke:
        """Create a no-stroke (invisible line)."""
        return cls(width_emu=0)

    @classmethod
    def solid(
        cls,
        color: ColorRef,
        width_pt: float = 1.0,
        cap: LineCap = LineCap.FLAT,
        join: LineJoin = LineJoin.ROUND,
    ) -> Stroke:
        """Create a solid stroke.

        Args:
            color: Stroke color
            width_pt: Width in points
            cap: Line end cap style
            join: Line join style
        """
        return cls(
            width_emu=int(width_pt * EMU_PER_POINT),
            color=color,
            dash=LineDash.SOLID,
            cap=cap,
            join=join,
        )

    @property
    def width_pt(self) -> float:
        """Width in points."""
        return self.width_emu / EMU_PER_POINT
