"""
Color representation and parsing for SVG.

Supports multiple color formats:
- Hex: #RGB, #RRGGBB
- RGB: rgb(r, g, b)
- RGBA: rgba(r, g, b, a)
- Named: CSS3 color names (140 colors)
"""

import re
from dataclasses import dataclass


@dataclass(frozen=True)
class Color:
    """
    Immutable RGBA color representation.

    Attributes:
        r: Red component (0-255)
        g: Green component (0-255)
        b: Blue component (0-255)
        a: Alpha component (0-255), 255 = fully opaque
    """

    r: int
    g: int
    b: int
    a: int = 255

    def __post_init__(self) -> None:
        """Validate color components are in valid range."""
        for component, value in [("r", self.r), ("g", self.g), ("b", self.b), ("a", self.a)]:
            if not 0 <= value <= 255:
                raise ValueError(f"Color {component} must be 0-255, got {value}")

    @classmethod
    def from_hex(cls, hex_str: str) -> "Color":
        """
        Parse color from hex format (#RGB or #RRGGBB).

        Args:
            hex_str: Hex color string (#RGB or #RRGGBB)

        Returns:
            Color instance

        Raises:
            ValueError: If hex string is invalid

        Examples:
            >>> Color.from_hex("#F00")
            Color(r=255, g=0, b=0, a=255)
            >>> Color.from_hex("#00FF00")
            Color(r=0, g=255, b=0, a=255)
        """
        hex_str = hex_str.strip()
        if not hex_str.startswith("#"):
            raise ValueError(f"Hex color must start with #, got: {hex_str}")

        hex_str = hex_str[1:]  # Remove #

        if len(hex_str) == 3:
            # #RGB -> #RRGGBB
            r = int(hex_str[0] * 2, 16)
            g = int(hex_str[1] * 2, 16)
            b = int(hex_str[2] * 2, 16)
        elif len(hex_str) == 6:
            # #RRGGBB
            r = int(hex_str[0:2], 16)
            g = int(hex_str[2:4], 16)
            b = int(hex_str[4:6], 16)
        else:
            raise ValueError(f"Hex color must be #RGB or #RRGGBB, got: #{hex_str}")

        return cls(r=r, g=g, b=b, a=255)

    @classmethod
    def from_rgb(cls, rgb_str: str) -> "Color":
        """
        Parse color from rgb(r, g, b) format.

        Args:
            rgb_str: RGB color string like "rgb(255, 0, 0)"

        Returns:
            Color instance

        Raises:
            ValueError: If RGB string is invalid

        Examples:
            >>> Color.from_rgb("rgb(255, 0, 0)")
            Color(r=255, g=0, b=0, a=255)
        """
        match = re.match(r"rgb\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*\)", rgb_str.strip())
        if not match:
            raise ValueError(f"Invalid rgb() format: {rgb_str}")

        r, g, b = map(int, match.groups())
        return cls(r=r, g=g, b=b, a=255)

    @classmethod
    def from_rgba(cls, rgba_str: str) -> "Color":
        """
        Parse color from rgba(r, g, b, a) format.

        Args:
            rgba_str: RGBA color string like "rgba(255, 0, 0, 0.5)"

        Returns:
            Color instance

        Raises:
            ValueError: If RGBA string is invalid

        Examples:
            >>> Color.from_rgba("rgba(255, 0, 0, 0.5)")
            Color(r=255, g=0, b=0, a=127)
        """
        match = re.match(
            r"rgba\s*\(\s*(\d+)\s*,\s*(\d+)\s*,\s*(\d+)\s*,\s*([\d.]+)\s*\)", rgba_str.strip()
        )
        if not match:
            raise ValueError(f"Invalid rgba() format: {rgba_str}")

        r, g, b = map(int, match.groups()[:3])
        a_float = float(match.group(4))
        a = int(a_float * 255) if a_float <= 1.0 else int(a_float)

        return cls(r=r, g=g, b=b, a=a)

    @classmethod
    def from_name(cls, name: str) -> "Color":
        """
        Parse color from CSS3 named color.

        Args:
            name: Color name (case-insensitive)

        Returns:
            Color instance

        Raises:
            ValueError: If color name is unknown

        Examples:
            >>> Color.from_name("red")
            Color(r=255, g=0, b=0, a=255)
            >>> Color.from_name("blue")
            Color(r=0, g=0, b=255, a=255)
        """
        name_lower = name.strip().lower()
        if name_lower not in CSS3_COLORS:
            raise ValueError(f"Unknown color name: {name}")

        hex_value = CSS3_COLORS[name_lower]
        return cls.from_hex(hex_value)

    @classmethod
    def parse(cls, color_str: str) -> "Color":
        """
        Parse color from any supported format.

        Automatically detects format and calls appropriate parsing method.
        Supports: hex (#RGB, #RRGGBB), rgb(), rgba(), and named colors.

        Args:
            color_str: Color string in any supported format.

        Returns:
            Color instance.

        Raises:
            ValueError: If color string is invalid or format is unknown.

        Examples:
            >>> Color.parse("#FF0000")
            Color(r=255, g=0, b=0, a=255)
            >>> Color.parse("rgb(0, 255, 0)")
            Color(r=0, g=255, b=0, a=255)
            >>> Color.parse("blue")
            Color(r=0, g=0, b=255, a=255)
        """
        color_str = color_str.strip()

        # Try hex format
        if color_str.startswith("#"):
            return cls.from_hex(color_str)

        # Try rgb() format
        if color_str.lower().startswith("rgb("):
            return cls.from_rgb(color_str)

        # Try rgba() format
        if color_str.lower().startswith("rgba("):
            return cls.from_rgba(color_str)

        # Try named color
        return cls.from_name(color_str)

    def to_tuple(self) -> tuple[int, int, int, int]:
        """
        Convert color to RGBA tuple.

        Returns:
            Tuple of (r, g, b, a) values

        Examples:
            >>> Color(255, 0, 0, 128).to_tuple()
            (255, 0, 0, 128)
        """
        return (self.r, self.g, self.b, self.a)

    def blend_with(self, background: "Color") -> "Color":
        """
        Alpha blend this color over a background color using Porter-Duff compositing.

        Uses "source over" compositing: C_out = C_src + C_bg * (1 - alpha_src)

        Args:
            background: Background color to blend over

        Returns:
            New blended color (always fully opaque)

        Examples:
            >>> fg = Color(255, 0, 0, 128)  # 50% red
            >>> bg = Color(0, 0, 255, 255)   # blue
            >>> result = fg.blend_with(bg)
            >>> result.r > result.b  # Result is reddish-purple
            True
        """
        # Normalize alpha to 0-1 range
        alpha_src = self.a / 255.0
        alpha_bg = background.a / 255.0

        # Porter-Duff "source over" compositing
        alpha_out = alpha_src + alpha_bg * (1 - alpha_src)

        if alpha_out == 0:
            return Color(0, 0, 0, 0)

        r_out = int((self.r * alpha_src + background.r * alpha_bg * (1 - alpha_src)) / alpha_out)
        g_out = int((self.g * alpha_src + background.g * alpha_bg * (1 - alpha_src)) / alpha_out)
        b_out = int((self.b * alpha_src + background.b * alpha_bg * (1 - alpha_src)) / alpha_out)
        a_out = int(alpha_out * 255)

        return Color(r=r_out, g=g_out, b=b_out, a=a_out)


# CSS3 Named Colors (140 colors)
CSS3_COLORS = {
    "aliceblue": "#F0F8FF",
    "antiquewhite": "#FAEBD7",
    "aqua": "#00FFFF",
    "aquamarine": "#7FFFD4",
    "azure": "#F0FFFF",
    "beige": "#F5F5DC",
    "bisque": "#FFE4C4",
    "black": "#000000",
    "blanchedalmond": "#FFEBCD",
    "blue": "#0000FF",
    "blueviolet": "#8A2BE2",
    "brown": "#A52A2A",
    "burlywood": "#DEB887",
    "cadetblue": "#5F9EA0",
    "chartreuse": "#7FFF00",
    "chocolate": "#D2691E",
    "coral": "#FF7F50",
    "cornflowerblue": "#6495ED",
    "cornsilk": "#FFF8DC",
    "crimson": "#DC143C",
    "cyan": "#00FFFF",
    "darkblue": "#00008B",
    "darkcyan": "#008B8B",
    "darkgoldenrod": "#B8860B",
    "darkgray": "#A9A9A9",
    "darkgrey": "#A9A9A9",
    "darkgreen": "#006400",
    "darkkhaki": "#BDB76B",
    "darkmagenta": "#8B008B",
    "darkolivegreen": "#556B2F",
    "darkorange": "#FF8C00",
    "darkorchid": "#9932CC",
    "darkred": "#8B0000",
    "darksalmon": "#E9967A",
    "darkseagreen": "#8FBC8F",
    "darkslateblue": "#483D8B",
    "darkslategray": "#2F4F4F",
    "darkslategrey": "#2F4F4F",
    "darkturquoise": "#00CED1",
    "darkviolet": "#9400D3",
    "deeppink": "#FF1493",
    "deepskyblue": "#00BFFF",
    "dimgray": "#696969",
    "dimgrey": "#696969",
    "dodgerblue": "#1E90FF",
    "firebrick": "#B22222",
    "floralwhite": "#FFFAF0",
    "forestgreen": "#228B22",
    "fuchsia": "#FF00FF",
    "gainsboro": "#DCDCDC",
    "ghostwhite": "#F8F8FF",
    "gold": "#FFD700",
    "goldenrod": "#DAA520",
    "gray": "#808080",
    "grey": "#808080",
    "green": "#008000",
    "greenyellow": "#ADFF2F",
    "honeydew": "#F0FFF0",
    "hotpink": "#FF69B4",
    "indianred": "#CD5C5C",
    "indigo": "#4B0082",
    "ivory": "#FFFFF0",
    "khaki": "#F0E68C",
    "lavender": "#E6E6FA",
    "lavenderblush": "#FFF0F5",
    "lawngreen": "#7CFC00",
    "lemonchiffon": "#FFFACD",
    "lightblue": "#ADD8E6",
    "lightcoral": "#F08080",
    "lightcyan": "#E0FFFF",
    "lightgoldenrodyellow": "#FAFAD2",
    "lightgray": "#D3D3D3",
    "lightgrey": "#D3D3D3",
    "lightgreen": "#90EE90",
    "lightpink": "#FFB6C1",
    "lightsalmon": "#FFA07A",
    "lightseagreen": "#20B2AA",
    "lightskyblue": "#87CEFA",
    "lightslategray": "#778899",
    "lightslategrey": "#778899",
    "lightsteelblue": "#B0C4DE",
    "lightyellow": "#FFFFE0",
    "lime": "#00FF00",
    "limegreen": "#32CD32",
    "linen": "#FAF0E6",
    "magenta": "#FF00FF",
    "maroon": "#800000",
    "mediumaquamarine": "#66CDAA",
    "mediumblue": "#0000CD",
    "mediumorchid": "#BA55D3",
    "mediumpurple": "#9370DB",
    "mediumseagreen": "#3CB371",
    "mediumslateblue": "#7B68EE",
    "mediumspringgreen": "#00FA9A",
    "mediumturquoise": "#48D1CC",
    "mediumvioletred": "#C71585",
    "midnightblue": "#191970",
    "mintcream": "#F5FFFA",
    "mistyrose": "#FFE4E1",
    "moccasin": "#FFE4B5",
    "navajowhite": "#FFDEAD",
    "navy": "#000080",
    "oldlace": "#FDF5E6",
    "olive": "#808000",
    "olivedrab": "#6B8E23",
    "orange": "#FFA500",
    "orangered": "#FF4500",
    "orchid": "#DA70D6",
    "palegoldenrod": "#EEE8AA",
    "palegreen": "#98FB98",
    "paleturquoise": "#AFEEEE",
    "palevioletred": "#DB7093",
    "papayawhip": "#FFEFD5",
    "peachpuff": "#FFDAB9",
    "peru": "#CD853F",
    "pink": "#FFC0CB",
    "plum": "#DDA0DD",
    "powderblue": "#B0E0E6",
    "purple": "#800080",
    "rebeccapurple": "#663399",
    "red": "#FF0000",
    "rosybrown": "#BC8F8F",
    "royalblue": "#4169E1",
    "saddlebrown": "#8B4513",
    "salmon": "#FA8072",
    "sandybrown": "#F4A460",
    "seagreen": "#2E8B57",
    "seashell": "#FFF5EE",
    "sienna": "#A0522D",
    "silver": "#C0C0C0",
    "skyblue": "#87CEEB",
    "slateblue": "#6A5ACD",
    "slategray": "#708090",
    "slategrey": "#708090",
    "snow": "#FFFAFA",
    "springgreen": "#00FF7F",
    "steelblue": "#4682B4",
    "tan": "#D2B48C",
    "teal": "#008080",
    "thistle": "#D8BFD8",
    "tomato": "#FF6347",
    "turquoise": "#40E0D0",
    "violet": "#EE82EE",
    "wheat": "#F5DEB3",
    "white": "#FFFFFF",
    "whitesmoke": "#F5F5F5",
    "yellow": "#FFFF00",
    "yellowgreen": "#9ACD32",
}
