"""
Firework system with Chinese New Year themed colors.
"""

import math
import random
from typing import List, Optional, Tuple, TYPE_CHECKING

from .particle import Particle
from .canvas import BrailleCanvas

if TYPE_CHECKING:
    from .sound import SoundManager


# Colorful firework palette (festive and vibrant)
CNY_COLORS = [
    # Reds (traditional CNY)
    (255, 0, 0),  # Bright Red
    (220, 20, 60),  # Crimson
    (255, 50, 50),  # Light Red
    # Golds/Yellows (prosperity)
    (255, 215, 0),  # Gold
    (255, 255, 0),  # Yellow
    (255, 223, 0),  # Golden Yellow
    # Oranges
    (255, 165, 0),  # Orange
    (255, 140, 0),  # Dark Orange
    # Pinks/Magentas
    (255, 0, 255),  # Magenta
    (255, 105, 180),  # Hot Pink
    (255, 20, 147),  # Deep Pink
    # Purples
    (148, 0, 211),  # Violet
    (186, 85, 211),  # Medium Orchid
    (238, 130, 238),  # Violet Light
    # Blues
    (0, 191, 255),  # Deep Sky Blue
    (30, 144, 255),  # Dodger Blue
    (0, 255, 255),  # Cyan
    # Greens
    (0, 255, 127),  # Spring Green
    (50, 205, 50),  # Lime Green
    (127, 255, 0),  # Chartreuse
    # White/Silver
    (255, 255, 255),  # White
    (192, 192, 192),  # Silver
]


class Firework:
    """A firework that launches, arcs, and explodes with CNY colors."""

    def __init__(
        self,
        canvas_width: int,
        canvas_height: int,
        camera_z: float = 0.0,
        sound_manager: Optional["SoundManager"] = None,
    ):
        """
        Initialize a firework.

        Args:
            canvas_width: Width of the canvas in pixels
            canvas_height: Height of the canvas in pixels
            camera_z: Current Z position of the camera
            sound_manager: Optional sound manager for playing sound effects
        """
        self.canvas_width = canvas_width
        self.canvas_height = canvas_height
        self.sound_manager = sound_manager

        # Random CNY color
        self.color = self._random_cny_color()

        # Launch from bottom of screen, always ahead of the camera
        self.x = random.uniform(canvas_width * 0.2, canvas_width * 0.8)
        self.y = canvas_height - 1
        # Spawn at camera position plus some forward distance
        self.z = camera_z + random.uniform(50.0, 300.0)

        # Calculate target explosion height (top 10% to top third of screen)
        self.target_y = random.uniform(canvas_height * 0.1, canvas_height * 0.33)

        # Calculate required launch velocity to reach target height
        gravity = 100.0
        distance_to_target = self.target_y - self.y
        required_velocity = math.sqrt(-2 * gravity * distance_to_target)

        # Launch velocity (upward with slight horizontal drift)
        self.vx = random.uniform(-20, 20)
        self.vy = -required_velocity
        self.vz = 0.0

        # Explosion parameters
        self.exploded = False
        self.particles: List[Particle] = []

        # Explode during ascent - random time before reaching apex
        ascent_time = abs(required_velocity / gravity)  # Time to reach apex
        self.explode_time = random.uniform(ascent_time * 0.6, ascent_time * 0.95)
        self.flight_time = 0.0

        # Trail particle for launch phase
        self.launch_trail: List[Tuple[float, float]] = []

    def _random_cny_color(self) -> str:
        """Generate a Chinese New Year themed color."""
        r, g, b = random.choice(CNY_COLORS)
        return BrailleCanvas.rgb_color(r, g, b)

    def update(self, dt: float):
        """
        Update firework state.

        Args:
            dt: Time delta in seconds
        """
        if not self.exploded:
            # Update launch phase
            gravity = 100.0
            self.vy += gravity * dt
            self.x += self.vx * dt
            self.y += self.vy * dt
            self.flight_time += dt

            # Store trail position
            self.launch_trail.append((self.x, self.y))
            if len(self.launch_trail) > 15:
                self.launch_trail.pop(0)

            # Explode during ascent when flight time reaches explode time
            if self.flight_time >= self.explode_time:
                self.explode()
        else:
            # Update explosion particles
            for particle in self.particles:
                particle.update(dt, gravity=50.0, air_resistance=0.97)

            # Remove dead particles
            self.particles = [p for p in self.particles if p.is_alive()]

    def explode(self):
        """Create explosion particles."""
        self.exploded = True

        # Play explosion sound with stereo positioning
        if self.sound_manager:
            self.sound_manager.play_explosion(self.x, self.canvas_width)

        # Generate particles in all directions
        num_particles = random.randint(450, 750)
        speed = random.uniform(140, 210)

        for _ in range(num_particles):
            # Random direction on a sphere
            theta = random.uniform(0, 2 * math.pi)
            phi = random.uniform(0, math.pi)

            # Convert to Cartesian coordinates
            vx = speed * math.sin(phi) * math.cos(theta)
            vy = speed * math.cos(phi)
            vz = speed * math.sin(phi) * math.sin(theta)

            # Random lifetime with some variation
            base_lifetime = random.uniform(1.8, 2.5)
            lifetime_variation = random.uniform(-0.2, 0.2)
            lifetime = base_lifetime + lifetime_variation

            particle = Particle(
                self.x, self.y, self.z, vx, vy, vz, self.color, lifetime
            )
            self.particles.append(particle)

    def render(self, canvas: BrailleCanvas, camera_z: float = 0.0):
        """
        Render firework to canvas.

        Args:
            canvas: BrailleCanvas to render to
            camera_z: Z position of the camera
        """
        if not self.exploded:
            # Render launch trail with perspective
            if self.launch_trail:
                points = []
                canvas_w = canvas.width
                canvas_h = canvas.height
                center_x = canvas_w / 2.0
                center_y = canvas_h / 2.0
                camera_distance = 200.0

                for x, y in self.launch_trail:
                    z_relative = self.z - camera_z
                    z_offset = z_relative + camera_distance

                    if z_offset > 0:
                        scale = camera_distance / z_offset
                        screen_x = center_x + (x - center_x) * scale
                        screen_y = center_y + (y - center_y) * scale

                        if 0 <= screen_x < canvas_w and 0 <= screen_y < canvas_h:
                            points.append((int(screen_x), int(screen_y)))

                if points:
                    canvas.plot(self.color, points)
        else:
            # Render explosion particles with perspective
            points = []
            canvas_w = canvas.width
            canvas_h = canvas.height
            center_x = canvas_w / 2.0
            center_y = canvas_h / 2.0
            camera_distance = 200.0

            for particle in self.particles:
                z_relative = particle.z - camera_z
                z_offset = z_relative + camera_distance

                if z_offset <= 0:
                    continue

                scale = camera_distance / z_offset
                screen_x = center_x + (particle.x - center_x) * scale
                screen_y = center_y + (particle.y - center_y) * scale

                x, y = int(screen_x), int(screen_y)
                if 0 <= x < canvas_w and 0 <= y < canvas_h:
                    points.append((x, y))

            if points:
                canvas.plot(self.color, points)

    def is_finished(self) -> bool:
        """Check if firework is finished (exploded and all particles dead)."""
        return self.exploded and len(self.particles) == 0
