import tkinter as tk
import random
import math
import time

class SnowGlobe:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("Snow Globe")
        self.root.geometry("400x400")
        self.root.configure(bg='lightblue')
        
        # Canvas for drawing snow
        self.canvas = tk.Canvas(self.root, width=380, height=380, bg='lightblue', highlightthickness=0)
        self.canvas.pack(padx=10, pady=10)
        
        # Snow particles
        self.snowflakes = []
        self.num_snowflakes = 100
        
        # Window position tracking for shake detection
        self.last_x = self.root.winfo_x()
        self.last_y = self.root.winfo_y()
        self.last_time = time.time()
        self.velocity_x = 0
        self.velocity_y = 0
        self.shake_intensity = 0
        
        # Physics constants
        self.gravity = 0.1
        self.friction = 0.98
        self.bounce_damping = 0.7
        
        self.create_snowflakes()
        self.animate()
        
        # Bind window movement events
        self.root.bind('<Configure>', self.on_window_move)
        
    def create_snowflakes(self):
        """Create initial snowflakes with random positions and properties"""
        for _ in range(self.num_snowflakes):
            snowflake = {
                'x': random.uniform(5, 375),
                'y': random.uniform(5, 375),
                'vx': 0,
                'vy': 0,
                'size': random.uniform(2, 6),
                'id': None
            }
            self.snowflakes.append(snowflake)
    
    def on_window_move(self, event):
        """Track window movement to detect shaking"""
        if event.widget == self.root:
            current_time = time.time()
            current_x = self.root.winfo_x()
            current_y = self.root.winfo_y()
            
            # Calculate time difference
            dt = current_time - self.last_time
            if dt > 0:
                # Calculate velocity based on position change
                self.velocity_x = (current_x - self.last_x) / dt
                self.velocity_y = (current_y - self.last_y) / dt
                
                # Calculate shake intensity based on velocity magnitude
                velocity_magnitude = math.sqrt(self.velocity_x**2 + self.velocity_y**2)
                self.shake_intensity = min(velocity_magnitude / 100, 10)  # Cap at 10
                
                # Apply shake force to snowflakes
                self.apply_shake_force()
                
                self.last_x = current_x
                self.last_y = current_y
                self.last_time = current_time
    
    def apply_shake_force(self):
        """Apply forces to snowflakes based on window shaking"""
        if self.shake_intensity > 0.1:  # Only apply if significant movement
            for snowflake in self.snowflakes:
                # Add random component to make it more realistic
                force_x = (self.velocity_x / 50) + random.uniform(-1, 1) * self.shake_intensity
                force_y = (self.velocity_y / 50) + random.uniform(-1, 1) * self.shake_intensity
                
                snowflake['vx'] += force_x
                snowflake['vy'] += force_y
    
    def update_snowflakes(self):
        """Update snowflake positions and handle physics"""
        for snowflake in self.snowflakes:
            # Apply gravity (always pulling down)
            snowflake['vy'] += self.gravity
            
            # Update positions
            snowflake['x'] += snowflake['vx']
            snowflake['y'] += snowflake['vy']
            
            # Apply friction
            snowflake['vx'] *= self.friction
            snowflake['vy'] *= self.friction
            
            # Boundary collisions with bounce
            if snowflake['x'] <= snowflake['size']:
                snowflake['x'] = snowflake['size']
                snowflake['vx'] = -snowflake['vx'] * self.bounce_damping
            elif snowflake['x'] >= 380 - snowflake['size']:
                snowflake['x'] = 380 - snowflake['size']
                snowflake['vx'] = -snowflake['vx'] * self.bounce_damping
            
            if snowflake['y'] <= snowflake['size']:
                snowflake['y'] = snowflake['size']
                snowflake['vy'] = -snowflake['vy'] * self.bounce_damping
            elif snowflake['y'] >= 380 - snowflake['size']:
                snowflake['y'] = 380 - snowflake['size']
                snowflake['vy'] = -snowflake['vy'] * self.bounce_damping
                # Extra damping when hitting bottom (like settling)
                snowflake['vx'] *= 0.8
    
    def draw_snowflakes(self):
        """Draw all snowflakes on the canvas"""
        self.canvas.delete("snowflake")
        
        for snowflake in self.snowflakes:
            x, y, size = snowflake['x'], snowflake['y'], snowflake['size']
            
            # Draw snowflake as a white circle
            self.canvas.create_oval(
                x - size, y - size, x + size, y + size,
                fill='white', outline='white', tags="snowflake"
            )
            
            # Add a sparkle effect for larger snowflakes
            if size > 4:
                self.canvas.create_oval(
                    x - 1, y - 1, x + 1, y + 1,
                    fill='lightcyan', outline='lightcyan', tags="snowflake"
                )
    
    def animate(self):
        """Main animation loop"""
        self.update_snowflakes()
        self.draw_snowflakes()
        
        # Gradually reduce shake intensity over time
        self.shake_intensity *= 0.95
        
        # Schedule next frame
        self.root.after(16, self.animate)  # ~60 FPS
    
    def run(self):
        """Start the snow globe application"""
        self.root.mainloop()

if __name__ == "__main__":
    snow_globe = SnowGlobe()
    snow_globe.run()