import pygame
import math
import random
import sys

# Initialize pygame
pygame.init()

# Screen dimensions
WIDTH, HEIGHT = 1200, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Thireus' Screensaver")

# Clock for controlling frame rate
clock = pygame.time.Clock()

# Particle class to represent each point in the simulation
class Particle:
    def __init__(self, x, y):
        self.pos = pygame.math.Vector2(x, y)
        angle = random.uniform(0, 2 * math.pi)
        self.vel = pygame.math.Vector2(math.cos(angle), math.sin(angle)) * random.uniform(0.5, 2.0)
        self.size = random.randint(2, 4)
        self.color = (
            random.randint(50, 255),
            random.randint(50, 255),
            random.randint(50, 255),
            180
        )
        self.base_size = self.size
        self.hue_shift = random.uniform(0, 360)
        self.hue_speed = random.uniform(0.1, 0.5)
        
    def update(self, time):
        # Add a subtle drift to create organic movement
        drift_x = math.sin(time * 0.1 + self.pos.y * 0.01) * 0.3
        drift_y = math.cos(time * 0.12 + self.pos.x * 0.01) * 0.3
        drift = pygame.math.Vector2(drift_x, drift_y)
        
        self.vel += drift
        self.vel.scale_to_length(min(self.vel.length(), 3.0))  # Limit maximum speed
        
        self.pos += self.vel
        
        # Bounce off edges
        if self.pos.x < 0 or self.pos.x > WIDTH:
            self.vel.x *= -1
            self.pos.x = max(0, min(self.pos.x, WIDTH))
        if self.pos.y < 0 or self.pos.y > HEIGHT:
            self.vel.y *= -1
            self.pos.y = max(0, min(self.pos.y, HEIGHT))
        
        # Pulsate size for more organic feel
        self.size = self.base_size * (0.8 + 0.3 * math.sin(time * 2 + self.pos.x * 0.05))
        
        # Shift color hue over time
        h = (self.hue_shift + time * self.hue_speed) % 360
        r, g, b = self.hsv_to_rgb(h, 0.8, 0.8)
        self.color = (r, g, b, 180)
    
    def draw(self, surface):
        pygame.draw.circle(surface, self.color, (int(self.pos.x), int(self.pos.y)), int(self.size))
    
    @staticmethod
    def hsv_to_rgb(h, s, v):
        h = h / 360.0
        if s == 0.0:
            r = g = b = v
        else:
            i = int(h * 6)
            f = (h * 6) - i
            p = v * (1 - s)
            q = v * (1 - s * f)
            t = v * (1 - s * (1 - f))
            i = i % 6
            if i == 0:
                r, g, b = v, t, p
            elif i == 1:
                r, g, b = q, v, p
            elif i == 2:
                r, g, b = p, v, t
            elif i == 3:
                r, g, b = p, q, v
            elif i == 4:
                r, g, b = t, p, v
            elif i == 5:
                r, g, b = v, p, q
        return int(r * 255), int(g * 255), int(b * 255)

# Create particles
particles = []
for _ in range(150):
    particles.append(Particle(random.randint(0, WIDTH), random.randint(0, HEIGHT)))

# Create a surface for trails effect
trail_surface = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)

# Main loop
running = True
start_time = pygame.time.get_ticks()
while running:
    current_time = (pygame.time.get_ticks() - start_time) / 1000.0
    
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE:
                running = False
    
    # Fade out previous frame for trails effect
    trail_surface.fill((0, 0, 0, 15), special_flags=pygame.BLEND_RGBA_SUB)
    
    # Update particles
    for particle in particles:
        particle.update(current_time)
    
    # Draw connections between nearby particles
    for i, particle1 in enumerate(particles):
        for particle2 in particles[i+1:]:
            distance = particle1.pos.distance_to(particle2.pos)
            if distance < 100:
                # Calculate alpha based on distance
                alpha = max(0, int(255 * (1 - distance/100)))
                # Calculate color gradient
                r = (particle1.color[0] + particle2.color[0]) // 2
                g = (particle1.color[1] + particle2.color[1]) // 2
                b = (particle1.color[2] + particle2.color[2]) // 2
                color = (r, g, b, alpha//3)
                
                # Draw line with varying thickness
                thickness = max(1, int(3 * (1 - distance/100)))
                pygame.draw.line(trail_surface, color, 
                                (int(particle1.pos.x), int(particle1.pos.y)),
                                (int(particle2.pos.x), int(particle2.pos.y)), 
                                thickness)
    
    # Draw particles
    for particle in particles:
        particle.draw(trail_surface)
    
    # Draw the trail surface to the main screen
    screen.fill((0, 0, 0))
    screen.blit(trail_surface, (0, 0))
    
    # Draw title
    font = pygame.font.SysFont(None, 36)
    title = font.render("Thireus' Screensaver - Press ESC to exit", True, (200, 200, 200))
    screen.blit(title, (WIDTH//2 - title.get_width()//2, 20))
    
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
sys.exit()