import argparse
import json
import math
import random
from typing import Dict, List, Optional


class AnimalAvatarGenerator:
    """A generator for animal-themed avatar SVGs."""

    # Constants
    ANIMALS = [
        "cat",
        "dog",
        "fox",
        "wolf",
        "bear",
        "panda",
        "koala",
        "tiger",
        "lion",
        "rabbit",
        "monkey",
        "elephant",
        "giraffe",
        "zebra",
        "penguin",
        "owl",
        "deer",
        "raccoon",
        "squirrel",
        "hedgehog",
        "otter",
        "frog",
    ]

    COLOR_PALETTES = {
        "natural": {
            "cat": [
                "#8B4513",
                "#A0522D",
                "#D2B48C",
                "#F5DEB3",
                "#000000",
                "#808080",
                "#FFFFFF",
                "#FFA500",
            ],
            "dog": [
                "#8B4513",
                "#A0522D",
                "#D2B48C",
                "#F5DEB3",
                "#000000",
                "#808080",
                "#FFFFFF",
                "#FFA500",
            ],
            "fox": ["#FF6600", "#FF7F00", "#FF8C00", "#FFA500", "#FFFFFF", "#000000"],
            "wolf": ["#808080", "#A9A9A9", "#D3D3D3", "#FFFFFF", "#000000", "#696969"],
            "bear": ["#8B4513", "#A0522D", "#D2B48C", "#F5DEB3", "#000000", "#FFFFFF"],
            "panda": ["#000000", "#FFFFFF"],
            "koala": ["#808080", "#A9A9A9", "#D3D3D3", "#FFFFFF", "#000000"],
            "tiger": ["#FF8C00", "#FF7F00", "#FFFFFF", "#000000"],
            "lion": ["#DAA520", "#B8860B", "#CD853F", "#D2B48C", "#FFFFFF", "#000000"],
            "rabbit": [
                "#FFFFFF",
                "#F5F5F5",
                "#D3D3D3",
                "#A9A9A9",
                "#FFC0CB",
                "#000000",
            ],
            "monkey": ["#8B4513", "#A0522D", "#D2B48C", "#F5DEB3", "#000000"],
            "elephant": ["#808080", "#A9A9A9", "#D3D3D3", "#FFFFFF", "#000000"],
            "giraffe": ["#DAA520", "#B8860B", "#F5DEB3", "#FFFFFF", "#000000"],
            "zebra": ["#000000", "#FFFFFF"],
            "penguin": ["#000000", "#FFFFFF", "#FFA500"],
            "owl": [
                "#8B4513",
                "#A0522D",
                "#D2B48C",
                "#F5DEB3",
                "#000000",
                "#FFFFFF",
                "#FFC0CB",
            ],
            "deer": ["#8B4513", "#A0522D", "#D2B48C", "#F5DEB3", "#FFFFFF", "#000000"],
            "raccoon": ["#808080", "#A9A9A9", "#D3D3D3", "#FFFFFF", "#000000"],
            "squirrel": ["#8B4513", "#A0522D", "#D2B48C", "#F5DEB3", "#000000"],
            "hedgehog": ["#8B4513", "#A0522D", "#D2B48C", "#F5DEB3", "#000000"],
            "otter": ["#8B4513", "#A0522D", "#D2B48C", "#F5DEB3", "#000000"],
            "frog": ["#008000", "#00FF00", "#ADFF2F", "#7FFF00", "#000000", "#FFFFFF"],
        },
        "pastel": {
            "all": [
                "#FFB6C1",
                "#FFD700",
                "#FFDAB9",
                "#98FB98",
                "#ADD8E6",
                "#DDA0DD",
                "#F0E68C",
                "#FFFFE0",
            ]
        },
        "vibrant": {
            "all": [
                "#FF0000",
                "#00FF00",
                "#0000FF",
                "#FFFF00",
                "#FF00FF",
                "#00FFFF",
                "#FFA500",
                "#FF1493",
            ]
        },
        "mono": {
            "all": ["#000000", "#333333", "#666666", "#999999", "#CCCCCC", "#FFFFFF"]
        },
    }

    EYE_STYLES = ["round", "oval", "almond", "wide", "narrow", "cute"]

    FACE_SHAPES = ["round", "oval", "square", "heart", "triangular", "diamond"]

    EAR_STYLES = {
        "cat": ["pointed", "folded", "round", "large", "small"],
        "dog": ["floppy", "pointed", "round", "large", "small"],
        "fox": ["pointed", "large", "small"],
        "wolf": ["pointed", "large", "small"],
        "bear": ["round", "small"],
        "panda": ["round", "small"],
        "koala": ["round", "large"],
        "tiger": ["round", "small"],
        "lion": ["round", "small"],
        "rabbit": ["long", "floppy", "standing"],
        "monkey": ["round", "small"],
        "elephant": ["large", "wide"],
        "giraffe": ["small", "pointed"],
        "zebra": ["pointed", "small"],
        "penguin": ["none"],
        "owl": ["none", "tufted"],
        "deer": ["small", "pointed"],
        "raccoon": ["round", "small"],
        "squirrel": ["pointed", "small"],
        "hedgehog": ["round", "small"],
        "otter": ["round", "small"],
        "frog": ["none"],
    }

    NOSE_STYLES = ["round", "triangular", "small", "large", "heart", "button"]

    SPECIAL_FEATURES = {
        "cat": ["whiskers", "stripes", "spots"],
        "dog": ["spots", "patch", "whiskers"],
        "fox": ["mask", "whiskers", "brush_tail"],
        "wolf": ["mask", "whiskers", "brush_tail"],
        "bear": ["none", "patch"],
        "panda": ["eye_patches", "none"],
        "koala": ["none", "nose_patch"],
        "tiger": ["stripes", "none"],
        "lion": ["mane", "none"],
        "rabbit": ["whiskers", "nose_patch"],
        "monkey": ["none", "cheek_patches"],
        "elephant": ["tusks", "none"],
        "giraffe": ["spots", "none"],
        "zebra": ["stripes", "none"],
        "penguin": ["bib", "none"],
        "owl": ["feather_tufts", "none"],
        "deer": ["antlers", "spots", "none"],
        "raccoon": ["mask", "whiskers", "none"],
        "squirrel": ["bushy_tail", "none"],
        "hedgehog": ["spikes", "none"],
        "otter": ["whiskers", "none"],
        "frog": ["spots", "none"],
    }

    EXPRESSIONS = ["happy", "serious", "surprised", "sleepy", "wink"]

    def __init__(self, seed: Optional[int] = None):
        """Initialize the avatar generator with an optional seed for reproducibility."""
        if seed is not None:
            random.seed(seed)

    def _get_colors(self, animal: str, color_palette: str) -> List[str]:
        """Get colors for the given animal and palette."""
        if color_palette in self.COLOR_PALETTES:
            if animal in self.COLOR_PALETTES[color_palette]:
                return self.COLOR_PALETTES[color_palette][animal]
            elif "all" in self.COLOR_PALETTES[color_palette]:
                return self.COLOR_PALETTES[color_palette]["all"]

        # Default to natural palette for the animal or general natural colors
        if animal in self.COLOR_PALETTES["natural"]:
            return self.COLOR_PALETTES["natural"][animal]

        # If no specific colors found, use a mix of browns and grays
        return [
            "#8B4513",
            "#A0522D",
            "#D2B48C",
            "#F5DEB3",
            "#808080",
            "#A9A9A9",
            "#FFFFFF",
        ]

    def _get_ear_style(self, animal: str) -> str:
        """Get a random ear style appropriate for the animal."""
        if animal in self.EAR_STYLES:
            return random.choice(self.EAR_STYLES[animal])
        return "none"  # Default for animals not in the list

    def _get_special_feature(self, animal: str) -> str:
        """Get a random special feature appropriate for the animal."""
        if animal in self.SPECIAL_FEATURES:
            return random.choice(self.SPECIAL_FEATURES[animal])
        return "none"  # Default for animals not in the list

    def _draw_circle(
        self,
        cx: float,
        cy: float,
        r: float,
        fill: str,
        stroke: str = "none",
        stroke_width: float = 1.0,
    ) -> str:
        """Generate SVG for a circle."""
        return f'<circle cx="{cx}" cy="{cy}" r="{r}" fill="{fill}" stroke="{stroke}" stroke-width="{stroke_width}" />'

    def _draw_ellipse(
        self,
        cx: float,
        cy: float,
        rx: float,
        ry: float,
        fill: str,
        stroke: str = "none",
        stroke_width: float = 1.0,
    ) -> str:
        """Generate SVG for an ellipse."""
        return f'<ellipse cx="{cx}" cy="{cy}" rx="{rx}" ry="{ry}" fill="{fill}" stroke="{stroke}" stroke-width="{stroke_width}" />'

    def _draw_path(
        self,
        d: str,
        fill: str,
        stroke: str = "none",
        stroke_width: float = 1.0,
        stroke_linecap: str = "round",
    ) -> str:
        """Generate SVG for a path."""
        return f'<path d="{d}" fill="{fill}" stroke="{stroke}" stroke-width="{stroke_width}" stroke-linecap="{stroke_linecap}" />'

    def _draw_polygon(
        self, points: str, fill: str, stroke: str = "none", stroke_width: float = 1.0
    ) -> str:
        """Generate SVG for a polygon."""
        return f'<polygon points="{points}" fill="{fill}" stroke="{stroke}" stroke-width="{stroke_width}" />'

    def _draw_face(
        self,
        animal: str,
        face_shape: str,
        face_color: str,
        x: float,
        y: float,
        size: float,
    ) -> str:
        """Draw the animal's face based on face shape."""
        elements = []

        if face_shape == "round":
            elements.append(self._draw_circle(x, y, size * 0.4, face_color))
        elif face_shape == "oval":
            elements.append(
                self._draw_ellipse(x, y, size * 0.35, size * 0.45, face_color)
            )
        elif face_shape == "square":
            points = (
                f"{x-size*0.35},{y-size*0.35} {x+size*0.35},{y-size*0.35} "
                f"{x+size*0.35},{y+size*0.35} {x-size*0.35},{y+size*0.35}"
            )
            elements.append(self._draw_polygon(points, face_color))
        elif face_shape == "heart":
            # Create a heart shape using paths
            cx, cy = x, y + size * 0.05
            r = size * 0.2
            path = (
                f"M {cx} {cy-r*0.4} "
                f"C {cx-r*1.5} {cy-r*1.5}, {cx-r*2} {cy+r*0.5}, {cx} {cy+r} "
                f"C {cx+r*2} {cy+r*0.5}, {cx+r*1.5} {cy-r*1.5}, {cx} {cy-r*0.4} Z"
            )
            elements.append(self._draw_path(path, face_color))
        elif face_shape == "triangular":
            points = (
                f"{x},{y-size*0.4} {x+size*0.4},{y+size*0.3} {x-size*0.4},{y+size*0.3}"
            )
            elements.append(self._draw_polygon(points, face_color))
        elif face_shape == "diamond":
            points = (
                f"{x},{y-size*0.4} {x+size*0.35},{y} {x},{y+size*0.4} {x-size*0.35},{y}"
            )
            elements.append(self._draw_polygon(points, face_color))

        return "\n".join(elements)

    def _draw_ears(
        self,
        animal: str,
        ear_style: str,
        face_color: str,
        inner_color: str,
        x: float,
        y: float,
        size: float,
    ) -> str:
        """Draw the animal's ears based on ear style."""
        elements = []

        if ear_style == "none":
            return ""

        if ear_style == "pointed":
            # Left ear
            points_left = f"{x-size*0.2},{y-size*0.1} {x-size*0.35},{y-size*0.45} {x-size*0.05},{y-size*0.15}"
            elements.append(self._draw_polygon(points_left, face_color))

            # Right ear
            points_right = f"{x+size*0.2},{y-size*0.1} {x+size*0.35},{y-size*0.45} {x+size*0.05},{y-size*0.15}"
            elements.append(self._draw_polygon(points_right, face_color))

            # Inner ears
            points_inner_left = f"{x-size*0.2},{y-size*0.13} {x-size*0.3},{y-size*0.38} {x-size*0.1},{y-size*0.17}"
            elements.append(self._draw_polygon(points_inner_left, inner_color))

            points_inner_right = f"{x+size*0.2},{y-size*0.13} {x+size*0.3},{y-size*0.38} {x+size*0.1},{y-size*0.17}"
            elements.append(self._draw_polygon(points_inner_right, inner_color))

        elif ear_style == "round":
            # Left ear
            elements.append(
                self._draw_circle(
                    x - size * 0.25, y - size * 0.25, size * 0.15, face_color
                )
            )

            # Right ear
            elements.append(
                self._draw_circle(
                    x + size * 0.25, y - size * 0.25, size * 0.15, face_color
                )
            )

            # Inner ears
            elements.append(
                self._draw_circle(
                    x - size * 0.25, y - size * 0.25, size * 0.08, inner_color
                )
            )
            elements.append(
                self._draw_circle(
                    x + size * 0.25, y - size * 0.25, size * 0.08, inner_color
                )
            )

        elif ear_style == "folded" or ear_style == "floppy":
            # Left ear
            path_left = (
                f"M {x-size*0.15} {y-size*0.15} "
                f"C {x-size*0.3} {y-size*0.4}, {x-size*0.4} {y-size*0.2}, {x-size*0.35} {y}"
            )
            elements.append(
                self._draw_path(
                    path_left, face_color, stroke="none", stroke_width=size * 0.08
                )
            )

            # Right ear
            path_right = (
                f"M {x+size*0.15} {y-size*0.15} "
                f"C {x+size*0.3} {y-size*0.4}, {x+size*0.4} {y-size*0.2}, {x+size*0.35} {y}"
            )
            elements.append(
                self._draw_path(
                    path_right, face_color, stroke="none", stroke_width=size * 0.08
                )
            )

        elif ear_style == "long" or ear_style == "standing":
            # Left ear
            points_left = f"{x-size*0.2},{y-size*0.15} {x-size*0.3},{y-size*0.6} {x-size*0.05},{y-size*0.15}"
            elements.append(self._draw_polygon(points_left, face_color))

            # Right ear
            points_right = f"{x+size*0.2},{y-size*0.15} {x+size*0.3},{y-size*0.6} {x+size*0.05},{y-size*0.15}"
            elements.append(self._draw_polygon(points_right, face_color))

            # Inner ears
            points_inner_left = f"{x-size*0.18},{y-size*0.18} {x-size*0.25},{y-size*0.5} {x-size*0.1},{y-size*0.18}"
            elements.append(self._draw_polygon(points_inner_left, inner_color))

            points_inner_right = f"{x+size*0.18},{y-size*0.18} {x+size*0.25},{y-size*0.5} {x+size*0.1},{y-size*0.18}"
            elements.append(self._draw_polygon(points_inner_right, inner_color))

        elif ear_style == "large":
            # Left ear
            elements.append(
                self._draw_ellipse(
                    x - size * 0.25, y - size * 0.3, size * 0.2, size * 0.25, face_color
                )
            )

            # Right ear
            elements.append(
                self._draw_ellipse(
                    x + size * 0.25, y - size * 0.3, size * 0.2, size * 0.25, face_color
                )
            )

            # Inner ears
            elements.append(
                self._draw_ellipse(
                    x - size * 0.25,
                    y - size * 0.3,
                    size * 0.1,
                    size * 0.15,
                    inner_color,
                )
            )
            elements.append(
                self._draw_ellipse(
                    x + size * 0.25,
                    y - size * 0.3,
                    size * 0.1,
                    size * 0.15,
                    inner_color,
                )
            )

        elif ear_style == "small":
            # Left ear
            elements.append(
                self._draw_ellipse(
                    x - size * 0.22,
                    y - size * 0.22,
                    size * 0.1,
                    size * 0.12,
                    face_color,
                )
            )

            # Right ear
            elements.append(
                self._draw_ellipse(
                    x + size * 0.22,
                    y - size * 0.22,
                    size * 0.1,
                    size * 0.12,
                    face_color,
                )
            )

            # Inner ears
            elements.append(
                self._draw_ellipse(
                    x - size * 0.22,
                    y - size * 0.22,
                    size * 0.05,
                    size * 0.06,
                    inner_color,
                )
            )
            elements.append(
                self._draw_ellipse(
                    x + size * 0.22,
                    y - size * 0.22,
                    size * 0.05,
                    size * 0.06,
                    inner_color,
                )
            )

        elif ear_style == "tufted" and animal == "owl":
            # Left ear tuft
            points_left = f"{x-size*0.2},{y-size*0.15} {x-size*0.35},{y-size*0.45} {x-size*0.05},{y-size*0.15}"
            elements.append(self._draw_polygon(points_left, face_color))

            # Right ear tuft
            points_right = f"{x+size*0.2},{y-size*0.15} {x+size*0.35},{y-size*0.45} {x+size*0.05},{y-size*0.15}"
            elements.append(self._draw_polygon(points_right, face_color))

        elif ear_style == "wide" and animal == "elephant":
            # Left ear
            path_left = (
                f"M {x-size*0.15} {y-size*0.1} "
                f"C {x-size*0.5} {y-size*0.2}, {x-size*0.6} {y+size*0.2}, {x-size*0.15} {y+size*0.2}"
            )
            elements.append(
                self._draw_path(
                    path_left, face_color, stroke=face_color, stroke_width=size * 0.04
                )
            )

            # Right ear
            path_right = (
                f"M {x+size*0.15} {y-size*0.1} "
                f"C {x+size*0.5} {y-size*0.2}, {x+size*0.6} {y+size*0.2}, {x+size*0.15} {y+size*0.2}"
            )
            elements.append(
                self._draw_path(
                    path_right, face_color, stroke=face_color, stroke_width=size * 0.04
                )
            )

        return "\n".join(elements)

    def _draw_eyes(
        self,
        eye_style: str,
        expression: str,
        eye_color: str,
        x: float,
        y: float,
        size: float,
    ) -> str:
        """Draw the animal's eyes based on eye style and expression."""
        elements = []
        eye_spacing = size * 0.2

        if eye_style == "round":
            eye_size = size * 0.08
            # Left eye
            elements.append(
                self._draw_circle(x - eye_spacing, y - size * 0.05, eye_size, "#FFFFFF")
            )
            elements.append(
                self._draw_circle(
                    x - eye_spacing, y - size * 0.05, eye_size * 0.6, eye_color
                )
            )

            # Right eye
            elements.append(
                self._draw_circle(x + eye_spacing, y - size * 0.05, eye_size, "#FFFFFF")
            )
            elements.append(
                self._draw_circle(
                    x + eye_spacing, y - size * 0.05, eye_size * 0.6, eye_color
                )
            )

        elif eye_style == "oval":
            eye_width = size * 0.1
            eye_height = size * 0.07
            # Left eye
            elements.append(
                self._draw_ellipse(
                    x - eye_spacing, y - size * 0.05, eye_width, eye_height, "#FFFFFF"
                )
            )
            elements.append(
                self._draw_ellipse(
                    x - eye_spacing,
                    y - size * 0.05,
                    eye_width * 0.6,
                    eye_height * 0.6,
                    eye_color,
                )
            )

            # Right eye
            elements.append(
                self._draw_ellipse(
                    x + eye_spacing, y - size * 0.05, eye_width, eye_height, "#FFFFFF"
                )
            )
            elements.append(
                self._draw_ellipse(
                    x + eye_spacing,
                    y - size * 0.05,
                    eye_width * 0.6,
                    eye_height * 0.6,
                    eye_color,
                )
            )

        elif eye_style == "almond":
            # Left eye - almond shape
            path_left = (
                f"M {x-eye_spacing-size*0.1} {y-size*0.05} "
                f"C {x-eye_spacing} {y-size*0.12}, {x-eye_spacing} {y+size*0.02}, {x-eye_spacing+size*0.1} {y-size*0.05} "
                f"C {x-eye_spacing} {y+size*0.02}, {x-eye_spacing} {y-size*0.12}, {x-eye_spacing-size*0.1} {y-size*0.05} Z"
            )
            elements.append(self._draw_path(path_left, "#FFFFFF"))
            elements.append(
                self._draw_circle(
                    x - eye_spacing, y - size * 0.05, size * 0.05, eye_color
                )
            )

            # Right eye - almond shape
            path_right = (
                f"M {x+eye_spacing-size*0.1} {y-size*0.05} "
                f"C {x+eye_spacing} {y-size*0.12}, {x+eye_spacing} {y+size*0.02}, {x+eye_spacing+size*0.1} {y-size*0.05} "
                f"C {x+eye_spacing} {y+size*0.02}, {x+eye_spacing} {y-size*0.12}, {x+eye_spacing-size*0.1} {y-size*0.05} Z"
            )
            elements.append(self._draw_path(path_right, "#FFFFFF"))
            elements.append(
                self._draw_circle(
                    x + eye_spacing, y - size * 0.05, size * 0.05, eye_color
                )
            )

        elif eye_style == "wide":
            eye_width = size * 0.12
            eye_height = size * 0.08
            # Left eye
            elements.append(
                self._draw_ellipse(
                    x - eye_spacing, y - size * 0.05, eye_width, eye_height, "#FFFFFF"
                )
            )
            elements.append(
                self._draw_ellipse(
                    x - eye_spacing,
                    y - size * 0.05,
                    eye_width * 0.5,
                    eye_height * 0.6,
                    eye_color,
                )
            )

            # Right eye
            elements.append(
                self._draw_ellipse(
                    x + eye_spacing, y - size * 0.05, eye_width, eye_height, "#FFFFFF"
                )
            )
            elements.append(
                self._draw_ellipse(
                    x + eye_spacing,
                    y - size * 0.05,
                    eye_width * 0.5,
                    eye_height * 0.6,
                    eye_color,
                )
            )

        elif eye_style == "narrow":
            eye_width = size * 0.12
            eye_height = size * 0.04
            # Left eye
            elements.append(
                self._draw_ellipse(
                    x - eye_spacing, y - size * 0.05, eye_width, eye_height, "#FFFFFF"
                )
            )
            elements.append(
                self._draw_ellipse(
                    x - eye_spacing,
                    y - size * 0.05,
                    eye_width * 0.4,
                    eye_height * 0.7,
                    eye_color,
                )
            )

            # Right eye
            elements.append(
                self._draw_ellipse(
                    x + eye_spacing, y - size * 0.05, eye_width, eye_height, "#FFFFFF"
                )
            )
            elements.append(
                self._draw_ellipse(
                    x + eye_spacing,
                    y - size * 0.05,
                    eye_width * 0.4,
                    eye_height * 0.7,
                    eye_color,
                )
            )

        elif eye_style == "cute":
            eye_size = size * 0.1
            # Left eye
            elements.append(
                self._draw_circle(x - eye_spacing, y - size * 0.05, eye_size, "#FFFFFF")
            )
            elements.append(
                self._draw_circle(
                    x - eye_spacing - size * 0.02,
                    y - size * 0.07,
                    eye_size * 0.5,
                    eye_color,
                )
            )
            elements.append(
                self._draw_circle(
                    x - eye_spacing - size * 0.03,
                    y - size * 0.08,
                    eye_size * 0.15,
                    "#FFFFFF",
                )
            )

            # Right eye
            elements.append(
                self._draw_circle(x + eye_spacing, y - size * 0.05, eye_size, "#FFFFFF")
            )
            elements.append(
                self._draw_circle(
                    x + eye_spacing - size * 0.02,
                    y - size * 0.07,
                    eye_size * 0.5,
                    eye_color,
                )
            )
            elements.append(
                self._draw_circle(
                    x + eye_spacing - size * 0.03,
                    y - size * 0.08,
                    eye_size * 0.15,
                    "#FFFFFF",
                )
            )

        # Apply expression
        if expression == "happy":
            # Close bottom half of eyes slightly
            path_left = (
                f"M {x-eye_spacing-size*0.1} {y-size*0.03} "
                f"Q {x-eye_spacing} {y+size*0.02}, {x-eye_spacing+size*0.1} {y-size*0.03}"
            )
            elements.append(
                self._draw_path(
                    path_left, face_color, stroke="#000000", stroke_width=size * 0.01
                )
            )

            path_right = (
                f"M {x+eye_spacing-size*0.1} {y-size*0.03} "
                f"Q {x+eye_spacing} {y+size*0.02}, {x+eye_spacing+size*0.1} {y-size*0.03}"
            )
            elements.append(
                self._draw_path(
                    path_right, face_color, stroke="#000000", stroke_width=size * 0.01
                )
            )

        elif expression == "serious":
            # Serious eyebrows
            path_left = (
                f"M {x-eye_spacing-size*0.08} {y-size*0.12} "
                f"L {x-eye_spacing+size*0.08} {y-size*0.15}"
            )
            elements.append(
                self._draw_path(
                    path_left, "none", stroke="#000000", stroke_width=size * 0.02
                )
            )

            path_right = (
                f"M {x+eye_spacing-size*0.08} {y-size*0.15} "
                f"L {x+eye_spacing+size*0.08} {y-size*0.12}"
            )
            elements.append(
                self._draw_path(
                    path_right, "none", stroke="#000000", stroke_width=size * 0.02
                )
            )

        elif expression == "surprised":
            # Raise eyebrows
            path_left = (
                f"M {x-eye_spacing-size*0.08} {y-size*0.15} "
                f"Q {x-eye_spacing} {y-size*0.18}, {x-eye_spacing+size*0.08} {y-size*0.15}"
            )
            elements.append(
                self._draw_path(
                    path_left, "none", stroke="#000000", stroke_width=size * 0.015
                )
            )

            path_right = (
                f"M {x+eye_spacing-size*0.08} {y-size*0.15} "
                f"Q {x+eye_spacing} {y-size*0.18}, {x+eye_spacing+size*0.08} {y-size*0.15}"
            )
            elements.append(
                self._draw_path(
                    path_right, "none", stroke="#000000", stroke_width=size * 0.015
                )
            )

        elif expression == "sleepy":
            # Half-closed eyes
            path_left = (
                f"M {x-eye_spacing-size*0.1} {y-size*0.08} "
                f"Q {x-eye_spacing} {y-size*0.01}, {x-eye_spacing+size*0.1} {y-size*0.08}"
            )
            elements.append(
                self._draw_path(
                    path_left, "none", stroke="#000000", stroke_width=size * 0.015
                )
            )

            path_right = (
                f"M {x+eye_spacing-size*0.1} {y-size*0.08} "
                f"Q {x+eye_spacing} {y-size*0.01}, {x+eye_spacing+size*0.1} {y-size*0.08}"
            )
            elements.append(
                self._draw_path(
                    path_right, "none", stroke="#000000", stroke_width=size * 0.015
                )
            )

        elif expression == "wink":
            # Right eye normal
            # Left eye winking
            path_left = (
                f"M {x-eye_spacing-size*0.1} {y-size*0.05} "
                f"Q {x-eye_spacing} {y-size*0.1}, {x-eye_spacing+size*0.1} {y-size*0.05}"
            )
            elements.append(
                self._draw_path(
                    path_left, "none", stroke="#000000", stroke_width=size * 0.02
                )
            )

        return "\n".join(elements)

    def _draw_nose(
        self,
        animal: str,
        nose_style: str,
        nose_color: str,
        x: float,
        y: float,
        size: float,
    ) -> str:
        """Draw the animal's nose based on nose style."""
        elements = []

        if nose_style == "round":
            elements.append(
                self._draw_circle(x, y + size * 0.05, size * 0.08, nose_color)
            )

        elif nose_style == "triangular":
            points = f"{x},{y+size*0.02} {x-size*0.08},{y+size*0.12} {x+size*0.08},{y+size*0.12}"
            elements.append(self._draw_polygon(points, nose_color))

        elif nose_style == "small":
            elements.append(
                self._draw_circle(x, y + size * 0.05, size * 0.05, nose_color)
            )

        elif nose_style == "large":
            if animal in ["dog", "bear", "panda", "koala"]:
                elements.append(
                    self._draw_ellipse(
                        x, y + size * 0.05, size * 0.1, size * 0.08, nose_color
                    )
                )
            else:
                elements.append(
                    self._draw_circle(x, y + size * 0.05, size * 0.1, nose_color)
                )

        elif nose_style == "heart":
            # Heart-shaped nose
            cx, cy = x, y + size * 0.05
            r = size * 0.06
            path = (
                f"M {cx} {cy-r*0.2} "
                f"C {cx-r*1.5} {cy-r*1.2}, {cx-r*1.8} {cy+r*0.6}, {cx} {cy+r*0.8} "
                f"C {cx+r*1.8} {cy+r*0.6}, {cx+r*1.5} {cy-r*1.2}, {cx} {cy-r*0.2} Z"
            )
            elements.append(self._draw_path(path, nose_color))

        elif nose_style == "button":
            elements.append(
                self._draw_circle(x, y + size * 0.05, size * 0.06, nose_color)
            )
            elements.append(
                self._draw_circle(
                    x,
                    y + size * 0.05,
                    size * 0.04,
                    nose_color,
                    stroke="#000000",
                    stroke_width=size * 0.01,
                )
            )

        return "\n".join(elements)

    def _draw_mouth(self, expression: str, x: float, y: float, size: float) -> str:
        """Draw the animal's mouth based on expression."""
        elements = []

        if expression == "happy":
            path = (
                f"M {x-size*0.15} {y+size*0.12} "
                f"Q {x} {y+size*0.25}, {x+size*0.15} {y+size*0.12}"
            )
            elements.append(
                self._draw_path(
                    path, "none", stroke="#000000", stroke_width=size * 0.02
                )
            )

        elif expression == "serious":
            path = f"M {x-size*0.12} {y+size*0.15} " f"L {x+size*0.12} {y+size*0.15}"
            elements.append(
                self._draw_path(
                    path, "none", stroke="#000000", stroke_width=size * 0.02
                )
            )

        elif expression == "surprised":
            elements.append(
                self._draw_ellipse(
                    x,
                    y + size * 0.15,
                    size * 0.06,
                    size * 0.08,
                    "#FFFFFF",
                    stroke="#000000",
                    stroke_width=size * 0.01,
                )
            )

        elif expression == "sleepy":
            path = (
                f"M {x-size*0.08} {y+size*0.15} "
                f"Q {x} {y+size*0.12}, {x+size*0.08} {y+size*0.15}"
            )
            elements.append(
                self._draw_path(
                    path, "none", stroke="#000000", stroke_width=size * 0.015
                )
            )

        elif expression == "wink":
            path = (
                f"M {x-size*0.15} {y+size*0.12} "
                f"Q {x} {y+size*0.22}, {x+size*0.15} {y+size*0.12}"
            )
            elements.append(
                self._draw_path(
                    path, "none", stroke="#000000", stroke_width=size * 0.02
                )
            )

        return "\n".join(elements)

    def _draw_special_features(
        self,
        animal: str,
        special_feature: str,
        face_color: str,
        accent_color: str,
        x: float,
        y: float,
        size: float,
    ) -> str:
        """Draw special features based on animal and feature type."""
        elements = []

        if special_feature == "none":
            return ""

        elif special_feature == "whiskers":
            # Left whiskers
            for i in range(3):
                angle = -30 + i * 30
                length = size * 0.25
                end_x = x - size * 0.15 + length * math.cos(math.radians(angle))
                end_y = y + size * 0.05 + length * math.sin(math.radians(angle))
                elements.append(
                    self._draw_path(
                        f"M {x-size*0.15} {y+size*0.05} L {end_x} {end_y}",
                        "none",
                        stroke="#000000",
                        stroke_width=size * 0.01,
                    )
                )

            # Right whiskers
            for i in range(3):
                angle = -150 + i * 30
                length = size * 0.25
                end_x = x + size * 0.15 + length * math.cos(math.radians(angle))
                end_y = y + size * 0.05 + length * math.sin(math.radians(angle))
                elements.append(
                    self._draw_path(
                        f"M {x+size*0.15} {y+size*0.05} L {end_x} {end_y}",
                        "none",
                        stroke="#000000",
                        stroke_width=size * 0.01,
                    )
                )

        elif special_feature == "stripes":
            # Vertical stripes
            if animal == "tiger":
                for i in range(3):
                    offset = -size * 0.2 + i * size * 0.2
                    path = (
                        f"M {x+offset} {y-size*0.3} "
                        f"Q {x+offset+size*0.1} {y}, {x+offset} {y+size*0.3}"
                    )
                    elements.append(
                        self._draw_path(
                            path, "none", stroke=accent_color, stroke_width=size * 0.04
                        )
                    )
            # Horizontal stripes for zebra
            elif animal == "zebra":
                for i in range(3):
                    offset = -size * 0.2 + i * size * 0.2
                    path = (
                        f"M {x-size*0.3} {y+offset} "
                        f"Q {x} {y+offset+size*0.1}, {x+size*0.3} {y+offset}"
                    )
                    elements.append(
                        self._draw_path(
                            path, "none", stroke=accent_color, stroke_width=size * 0.04
                        )
                    )

        elif special_feature == "spots":
            # Random spots
            num_spots = random.randint(3, 6)
            for _ in range(num_spots):
                spot_x = x + random.uniform(-size * 0.3, size * 0.3)
                spot_y = y + random.uniform(-size * 0.3, size * 0.3)
                spot_size = random.uniform(size * 0.03, size * 0.08)
                elements.append(
                    self._draw_circle(spot_x, spot_y, spot_size, accent_color)
                )

        elif special_feature == "patch":
            # Eye patch or face patch
            if animal == "dog":
                elements.append(
                    self._draw_ellipse(
                        x - size * 0.2, y, size * 0.2, size * 0.25, accent_color
                    )
                )
            else:
                # Generic face patch
                elements.append(
                    self._draw_ellipse(
                        x, y + size * 0.2, size * 0.2, size * 0.15, accent_color
                    )
                )

        elif special_feature == "mask":
            if animal == "raccoon":
                # Raccoon mask
                path = (
                    f"M {x-size*0.3} {y-size*0.1} "
                    f"Q {x} {y-size*0.3}, {x+size*0.3} {y-size*0.1} "
                    f"Q {x+size*0.2} {y+size*0.1}, {x} {y+size*0.15} "
                    f"Q {x-size*0.2} {y+size*0.1}, {x-size*0.3} {y-size*0.1} Z"
                )
                elements.append(self._draw_path(path, accent_color))
            elif animal in ["fox", "wolf"]:
                # Fox/wolf mask
                path = (
                    f"M {x-size*0.3} {y-size*0.1} "
                    f"L {x} {y+size*0.1} "
                    f"L {x+size*0.3} {y-size*0.1} "
                    f"Q {x+size*0.15} {y-size*0.05}, {x} {y-size*0.1} "
                    f"Q {x-size*0.15} {y-size*0.05}, {x-size*0.3} {y-size*0.1} Z"
                )
                elements.append(self._draw_path(path, accent_color))

        elif special_feature == "eye_patches" and animal == "panda":
            # Panda eye patches
            elements.append(
                self._draw_ellipse(
                    x - size * 0.2,
                    y - size * 0.05,
                    size * 0.15,
                    size * 0.2,
                    accent_color,
                )
            )
            elements.append(
                self._draw_ellipse(
                    x + size * 0.2,
                    y - size * 0.05,
                    size * 0.15,
                    size * 0.2,
                    accent_color,
                )
            )

        elif special_feature == "nose_patch":
            elements.append(
                self._draw_ellipse(
                    x, y + size * 0.05, size * 0.12, size * 0.1, accent_color
                )
            )

        elif special_feature == "mane" and animal == "lion":
            # Lion mane
            for i in range(12):
                angle = i * 30
                outer_x = x + size * 0.5 * math.cos(math.radians(angle))
                outer_y = y + size * 0.5 * math.sin(math.radians(angle))
                inner_x = x + size * 0.3 * math.cos(math.radians(angle))
                inner_y = y + size * 0.3 * math.sin(math.radians(angle))

                # Draw mane sections
                path = (
                    f"M {inner_x} {inner_y} "
                    f"L {outer_x} {outer_y} "
                    f"A {size*0.5} {size*0.5} 0 0 1 "
                    f"{x + size * 0.5 * math.cos(math.radians(angle + 30))} "
                    f"{y + size * 0.5 * math.sin(math.radians(angle + 30))} "
                    f"L {x + size * 0.3 * math.cos(math.radians(angle + 30))} "
                    f"{y + size * 0.3 * math.sin(math.radians(angle + 30))} Z"
                )
                elements.append(self._draw_path(path, accent_color))

        elif special_feature == "tusks" and animal == "elephant":
            # Elephant tusks
            path_left = (
                f"M {x-size*0.15} {y+size*0.1} "
                f"Q {x-size*0.3} {y+size*0.3}, {x-size*0.35} {y+size*0.5}"
            )
            elements.append(
                self._draw_path(
                    path_left, "#FFFFF0", stroke="#F5F5DC", stroke_width=size * 0.04
                )
            )

            path_right = (
                f"M {x+size*0.15} {y+size*0.1} "
                f"Q {x+size*0.3} {y+size*0.3}, {x+size*0.35} {y+size*0.5}"
            )
            elements.append(
                self._draw_path(
                    path_right, "#FFFFF0", stroke="#F5F5DC", stroke_width=size * 0.04
                )
            )

        elif special_feature == "antlers" and animal == "deer":
            # Deer antlers
            # Left antler
            path_left = (
                f"M {x-size*0.15} {y-size*0.2} "
                f"L {x-size*0.3} {y-size*0.45} "
                f"L {x-size*0.4} {y-size*0.4} "
                f"M {x-size*0.3} {y-size*0.45} "
                f"L {x-size*0.2} {y-size*0.5}"
            )
            elements.append(
                self._draw_path(
                    path_left, "none", stroke=accent_color, stroke_width=size * 0.03
                )
            )

            # Right antler
            path_right = (
                f"M {x+size*0.15} {y-size*0.2} "
                f"L {x+size*0.3} {y-size*0.45} "
                f"L {x+size*0.4} {y-size*0.4} "
                f"M {x+size*0.3} {y-size*0.45} "
                f"L {x+size*0.2} {y-size*0.5}"
            )
            elements.append(
                self._draw_path(
                    path_right, "none", stroke=accent_color, stroke_width=size * 0.03
                )
            )

        elif special_feature == "bushy_tail" and animal == "squirrel":
            # Squirrel bushy tail
            path = (
                f"M {x+size*0.1} {y+size*0.2} "
                f"Q {x+size*0.5} {y}, {x+size*0.3} {y-size*0.3} "
                f"Q {x+size*0.4} {y-size*0.4}, {x+size*0.5} {y-size*0.35} "
                f"Q {x+size*0.45} {y-size*0.25}, {x+size*0.6} {y-size*0.3} "
                f"Q {x+size*0.55} {y-size*0.1}, {x+size*0.4} {y+size*0.1} "
                f"Q {x+size*0.3} {y+size*0.3}, {x+size*0.1} {y+size*0.2} Z"
            )
            elements.append(self._draw_path(path, accent_color))

        elif special_feature == "brush_tail" and animal in ["fox", "wolf"]:
            # Fox/wolf brush tail
            path = (
                f"M {x+size*0.1} {y+size*0.2} "
                f"Q {x+size*0.4} {y+size*0.1}, {x+size*0.5} {y-size*0.1} "
                f"Q {x+size*0.6} {y-size*0.2}, {x+size*0.7} {y-size*0.1} "
                f"Q {x+size*0.65} {y}, {x+size*0.6} {y+size*0.1} "
                f"Q {x+size*0.5} {y+size*0.2}, {x+size*0.3} {y+size*0.3} Z"
            )
            elements.append(self._draw_path(path, face_color))
            # Tail tip
            elements.append(
                self._draw_ellipse(
                    x + size * 0.6,
                    y - size * 0.05,
                    size * 0.12,
                    size * 0.08,
                    accent_color,
                )
            )

        elif special_feature == "bib" and animal == "penguin":
            # Penguin bib/chest
            path = (
                f"M {x-size*0.2} {y} "
                f"Q {x} {y+size*0.4}, {x+size*0.2} {y} "
                f"Q {x} {y+size*0.1}, {x-size*0.2} {y} Z"
            )
            elements.append(self._draw_path(path, "#FFFFFF"))

        elif special_feature == "feather_tufts" and animal == "owl":
            # Owl feather tufts
            path_left = (
                f"M {x-size*0.1} {y-size*0.3} "
                f"Q {x-size*0.15} {y-size*0.45}, {x-size*0.05} {y-size*0.5}"
            )
            elements.append(
                self._draw_path(
                    path_left, face_color, stroke="#000000", stroke_width=size * 0.01
                )
            )

            path_right = (
                f"M {x+size*0.1} {y-size*0.3} "
                f"Q {x+size*0.15} {y-size*0.45}, {x+size*0.05} {y-size*0.5}"
            )
            elements.append(
                self._draw_path(
                    path_right, face_color, stroke="#000000", stroke_width=size * 0.01
                )
            )

        elif special_feature == "spikes" and animal == "hedgehog":
            # Hedgehog spikes
            for i in range(12):
                angle = i * 30
                inner_x = x + size * 0.3 * math.cos(math.radians(angle))
                inner_y = y + size * 0.3 * math.sin(math.radians(angle))
                outer_x = x + size * 0.5 * math.cos(math.radians(angle))
                outer_y = y + size * 0.5 * math.sin(math.radians(angle))

                path = f"M {inner_x} {inner_y} L {outer_x} {outer_y}"
                elements.append(
                    self._draw_path(
                        path, "none", stroke=accent_color, stroke_width=size * 0.03
                    )
                )

        elif special_feature == "cheek_patches" and animal == "monkey":
            # Monkey cheek patches
            elements.append(
                self._draw_circle(
                    x - size * 0.25, y + size * 0.1, size * 0.12, accent_color
                )
            )
            elements.append(
                self._draw_circle(
                    x + size * 0.25, y + size * 0.1, size * 0.12, accent_color
                )
            )

        return "\n".join(elements)

    def generate_avatar(
        self,
        animal: Optional[str] = None,
        color_palette: str = "natural",
        face_shape: Optional[str] = None,
        eye_style: Optional[str] = None,
        ear_style: Optional[str] = None,
        nose_style: Optional[str] = None,
        expression: Optional[str] = None,
        special_feature: Optional[str] = None,
        size: int = 500,
    ) -> str:
        """
        Generate an animal avatar with the specified parameters.

        Args:
            animal: Animal type (e.g., "cat", "dog"). If None, a random animal is selected.
            color_palette: Color palette to use (e.g., "natural", "pastel", "vibrant", "mono").
            face_shape: Shape of the face. If None, a random shape is selected.
            eye_style: Style of the eyes. If None, a random style is selected.
            ear_style: Style of the ears. If None, a random style is selected for the animal.
            nose_style: Style of the nose. If None, a random style is selected.
            expression: Facial expression. If None, a random expression is selected.
            special_feature: Special feature to add. If None, a random feature is selected for the animal.
            size: Size of the avatar in pixels.

        Returns:
            SVG string representation of the generated avatar.
        """
        # Select random animal if not specified
        if animal is None or animal not in self.ANIMALS:
            animal = random.choice(self.ANIMALS)

        # Select random options if not specified
        if face_shape is None or face_shape not in self.FACE_SHAPES:
            face_shape = random.choice(self.FACE_SHAPES)

        if eye_style is None or eye_style not in self.EYE_STYLES:
            eye_style = random.choice(self.EYE_STYLES)

        if ear_style is None:
            ear_style = self._get_ear_style(animal)

        if nose_style is None or nose_style not in self.NOSE_STYLES:
            nose_style = random.choice(self.NOSE_STYLES)

        if expression is None or expression not in self.EXPRESSIONS:
            expression = random.choice(self.EXPRESSIONS)

        if special_feature is None:
            special_feature = self._get_special_feature(animal)

        # Get colors
        colors = self._get_colors(animal, color_palette)
        face_color = random.choice(colors)

        # Make sure accent color is different from face color
        remaining_colors = [c for c in colors if c != face_color]
        if not remaining_colors:
            remaining_colors = ["#000000", "#FFFFFF"]
        accent_color = random.choice(remaining_colors)

        # Ensure inner ear color is different from face color
        inner_ear_color = random.choice(remaining_colors)

        # Eye color options
        eye_colors = ["#000000", "#331800", "#0000FF", "#008000", "#FFA500", "#800080"]
        eye_color = random.choice(eye_colors)

        # Nose color options based on animal
        if animal in [
            "dog",
            "cat",
            "fox",
            "wolf",
            "bear",
            "panda",
            "koala",
            "tiger",
            "lion",
        ]:
            nose_color = "#000000"
        else:
            nose_color = accent_color

        # Center coordinates
        x, y = size / 2, size / 2

        # Generate SVG elements
        elements = []

        # Draw the face first
        elements.append(self._draw_face(animal, face_shape, face_color, x, y, size))

        # Draw special features behind the face if needed
        if special_feature in ["mane", "spikes"]:
            elements.append(
                self._draw_special_features(
                    animal, special_feature, face_color, accent_color, x, y, size
                )
            )

        # Draw ears
        elements.append(
            self._draw_ears(animal, ear_style, face_color, inner_ear_color, x, y, size)
        )

        # Draw eyes
        elements.append(self._draw_eyes(eye_style, expression, eye_color, x, y, size))

        # Draw nose
        elements.append(self._draw_nose(animal, nose_style, nose_color, x, y, size))

        # Draw mouth
        elements.append(self._draw_mouth(expression, x, y, size))

        # Draw special features that should be in front
        if special_feature not in ["mane", "spikes"]:
            elements.append(
                self._draw_special_features(
                    animal, special_feature, face_color, accent_color, x, y, size
                )
            )

        # Assemble SVG
        svg_content = "\n".join(elements)
        svg = (
            f'<svg viewBox="0 0 {size} {size}" xmlns="http://www.w3.org/2000/svg">\n'
            f"{svg_content}\n"
            f"</svg>"
        )

        return svg

    def get_avatar_options(self) -> Dict[str, List[str]]:
        """Return all available avatar options."""
        return {
            "animals": self.ANIMALS,
            "color_palettes": list(self.COLOR_PALETTES.keys()),
            "face_shapes": self.FACE_SHAPES,
            "eye_styles": self.EYE_STYLES,
            "ear_styles": dict(self.EAR_STYLES.items()),
            "nose_styles": self.NOSE_STYLES,
            "expressions": self.EXPRESSIONS,
            "special_features": dict(self.SPECIAL_FEATURES.items()),
        }

    def generate_random_avatar(self, size: int = 500) -> str:
        """Generate a completely random avatar."""
        return self.generate_avatar(size=size)


def generate_avatar_with_options(options: Dict) -> str:
    """Generate an avatar with the given options."""
    generator = AnimalAvatarGenerator(seed=options.get("seed"))

    return generator.generate_avatar(
        animal=options.get("animal"),
        color_palette=options.get("color_palette", "natural"),
        face_shape=options.get("face_shape"),
        eye_style=options.get("eye_style"),
        ear_style=options.get("ear_style"),
        nose_style=options.get("nose_style"),
        expression=options.get("expression"),
        special_feature=options.get("special_feature"),
        size=options.get("size", 500),
    )


def list_avatar_options() -> Dict[str, List[str]]:
    """Return all available avatar options."""
    generator = AnimalAvatarGenerator()
    return generator.get_avatar_options()


def create_avatar_app():
    """Command-line interface for the avatar generator."""
    parser = argparse.ArgumentParser(description="Generate animal avatars")
    parser.add_argument(
        "--animal", help="Animal type", choices=AnimalAvatarGenerator.ANIMALS
    )
    parser.add_argument(
        "--color-palette",
        help="Color palette",
        default="natural",
        choices=["natural", "pastel", "vibrant", "mono"],
    )
    parser.add_argument(
        "--face-shape", help="Face shape", choices=AnimalAvatarGenerator.FACE_SHAPES
    )
    parser.add_argument(
        "--eye-style", help="Eye style", choices=AnimalAvatarGenerator.EYE_STYLES
    )
    parser.add_argument("--ear-style", help="Ear style")
    parser.add_argument(
        "--nose-style", help="Nose style", choices=AnimalAvatarGenerator.NOSE_STYLES
    )
    parser.add_argument(
        "--expression", help="Expression", choices=AnimalAvatarGenerator.EXPRESSIONS
    )
    parser.add_argument("--special-feature", help="Special feature")
    parser.add_argument("--size", help="Size in pixels", type=int, default=500)
    parser.add_argument("--seed", help="Random seed for reproducibility", type=int)
    parser.add_argument("--output", help="Output file path", default="avatar.svg")
    parser.add_argument(
        "--list-options", help="List all available options", action="store_true"
    )

    args = parser.parse_args()

    if args.list_options:
        options = list_avatar_options()
        print(json.dumps(options, indent=2))
        return

    generator = AnimalAvatarGenerator(seed=args.seed)

    svg = generator.generate_avatar(
        animal=args.animal,
        color_palette=args.color_palette,
        face_shape=args.face_shape,
        eye_style=args.eye_style,
        ear_style=args.ear_style,
        nose_style=args.nose_style,
        expression=args.expression,
        special_feature=args.special_feature,
        size=args.size,
    )

    with open(args.output, "w") as f:
        f.write(svg)

    print(f"Avatar saved to {args.output}")


if __name__ == "__main__":
    create_avatar_app()
