import pygame
import random
import math

# Initialize pygame
pygame.init()

# Screen dimensions and panel sizes
WIDTH, HEIGHT = 800, 600
PANEL_HEIGHT = 150  # Bottom panel for sliders
SIM_HEIGHT = HEIGHT - PANEL_HEIGHT  # Simulation area height

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Particle Simulation with Adjustable Variables")
clock = pygame.time.Clock()

# Define a simple Slider class
class Slider:
    def __init__(self, x, y, w, h, min_val, max_val, init_val, label):
        self.x = x
        self.y = y
        self.w = w
        self.h = h
        self.min_val = min_val
        self.max_val = max_val
        self.value = init_val
        self.label = label
        self.dragging = False

    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                if self.get_knob_rect().collidepoint(event.pos):
                    self.dragging = True
        elif event.type == pygame.MOUSEBUTTONUP:
            if event.button == 1:
                self.dragging = False
        elif event.type == pygame.MOUSEMOTION:
            if self.dragging:
                mx = event.pos[0]
                # Clamp mx inside slider range
                relative = (mx - self.x) / self.w
                relative = max(0, min(1, relative))
                self.value = self.min_val + relative * (self.max_val - self.min_val)

    def get_knob_rect(self):
        # Determine knob position along slider track
        relative = (self.value - self.min_val) / (self.max_val - self.min_val)
        knob_x = self.x + relative * self.w
        knob_width = 10
        knob_height = self.h
        return pygame.Rect(knob_x - knob_width // 2, self.y, knob_width, knob_height)

    def draw(self, surface, font):
        # Draw slider track (a thin rectangle)
        track_rect = pygame.Rect(self.x, self.y + self.h // 2 - 2, self.w, 4)
        pygame.draw.rect(surface, (200, 200, 200), track_rect)
        # Draw knob
        knob_rect = self.get_knob_rect()
        pygame.draw.rect(surface, (100, 100, 100), knob_rect)
        # Draw label and current value (as plain text)
        label_surface = font.render(f"{self.label}: {self.value:.2f}", True, (0, 0, 0))
        surface.blit(label_surface, (self.x, self.y - 20))

# Particle class
class Particle:
    def __init__(self, pos, velocity, lifetime, size, color=(255, 255, 255)):
        self.pos = pygame.math.Vector2(pos)
        self.vel = pygame.math.Vector2(velocity)
        self.lifetime = lifetime
        self.size = size
        self.initial_lifetime = lifetime
        self.color = color

    def update(self, gravity):
        self.vel.y += gravity
        self.pos += self.vel
        self.lifetime -= 1

    def is_dead(self):
        return self.lifetime <= 0

    def draw(self, surface, glow_intensity):
        # Draw glow effect if glow_intensity is greater than zero
        if glow_intensity > 0:
            # Create a temporary surface for glow with per-pixel alpha
            glow_surface = pygame.Surface((self.size*6, self.size*6), pygame.SRCALPHA)
            glow_center = self.size * 3
            # Draw several concentric circles for the glow effect
            for i in range(1, 6):
                # Alpha decreases as the circle radius increases
                alpha = max(0, int(255 * (glow_intensity / 10) * (1 - i/6)))
                radius = int(self.size + i * 2)
                pygame.draw.circle(glow_surface,
                                   (self.color[0], self.color[1], self.color[2], alpha),
                                   (glow_center, glow_center),
                                   radius)
            # Blit the glow surface with additive blending
            surface.blit(glow_surface, (self.pos.x - self.size*3, self.pos.y - self.size*3), special_flags=pygame.BLEND_RGBA_ADD)
        # Draw the particle itself
        pygame.draw.circle(surface, self.color, (int(self.pos.x), int(self.pos.y)), int(self.size))

# Create sliders for each variable, arranged in two rows within the bottom panel.
font = pygame.font.SysFont("Arial", 16)
sliders = []
# Row 1: Emission Rate, Speed, Lifetime
sliders.append(Slider(x=20, y=SIM_HEIGHT + 10,  w=200, h=20, min_val=0,  max_val=50,  init_val=5,   label="Emission Rate"))
sliders.append(Slider(x=240, y=SIM_HEIGHT + 10, w=200, h=20, min_val=0,  max_val=10,  init_val=5,   label="Speed"))
sliders.append(Slider(x=460, y=SIM_HEIGHT + 10, w=200, h=20, min_val=10, max_val=300, init_val=100, label="Lifetime"))
# Row 2: Size, Gravity, Glow
sliders.append(Slider(x=20, y=SIM_HEIGHT + 50, w=200, h=20, min_val=1,  max_val=20,  init_val=5,   label="Size"))
sliders.append(Slider(x=240, y=SIM_HEIGHT + 50, w=200, h=20, min_val=0,  max_val=2,   init_val=0.1, label="Gravity"))
sliders.append(Slider(x=460, y=SIM_HEIGHT + 50, w=200, h=20, min_val=0,  max_val=10,  init_val=3,   label="Glow"))

# List to hold all particles
particles = []

# Emitter position (center of simulation area)
emitter = pygame.math.Vector2(WIDTH // 2, SIM_HEIGHT // 2)

# Main loop
running = True
while running:
    # Process events (for quitting and slider events)
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        for slider in sliders:
            slider.handle_event(event)

    # Get simulation variables from slider values
    emission_rate = sliders[0].value      # particles per frame
    speed = sliders[1].value              # initial speed magnitude
    lifetime = sliders[2].value           # lifetime in frames
    size = sliders[3].value               # particle size (radius)
    gravity = sliders[4].value            # gravity acceleration
    glow = sliders[5].value               # glow intensity

    # Spawn new particles (round emission_rate to an integer count)
    for _ in range(int(emission_rate)):
        # Spawn at the emitter with a random direction
        angle = random.uniform(0, 2 * math.pi)
        velocity = pygame.math.Vector2(math.cos(angle), math.sin(angle)) * speed
        particles.append(Particle(emitter, velocity, lifetime, size))

    # Update particles and remove dead ones
    for particle in particles[:]:
        particle.update(gravity)
        if particle.is_dead():
            particles.remove(particle)

    # Clear simulation area (fill with black)
    screen.fill((0, 0, 0), rect=pygame.Rect(0, 0, WIDTH, SIM_HEIGHT))
    # Optionally fill the control area with a light color (or leave it as is)
    screen.fill((220, 220, 220), rect=pygame.Rect(0, SIM_HEIGHT, WIDTH, PANEL_HEIGHT))

    # Draw all particles
    for particle in particles:
        particle.draw(screen, glow_intensity=glow)

    # Draw slider controls in the bottom panel
    for slider in sliders:
        slider.draw(screen, font)

    # Draw debug text (plain text, no background) at the top-left corner of the simulation area
    debug_text = (f"Particles: {len(particles)} | Emission Rate: {emission_rate:.2f} | Speed: {speed:.2f} | "
                  f"Lifetime: {lifetime:.2f} | Size: {size:.2f} | Gravity: {gravity:.2f} | Glow: {glow:.2f}")
    debug_surface = font.render(debug_text, True, (255, 255, 255))
    screen.blit(debug_surface, (10, 10))

    pygame.display.flip()
    clock.tick(60)

pygame.quit()
