import pygame
import sys
import random
import math

pygame.init()
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Clean Master – Multi‑Level Edition")
clock = pygame.time.Clock()
FPS = 60

# ==================== COLORS ====================
WHITE       = (255, 255, 255)
BLACK       = (0, 0, 0)
SKY_BLUE    = (135, 206, 235)
GRASS_GREEN = (120, 200, 80)
SUN_YELLOW  = (255, 230, 100)
WOOD_LIGHT  = (160, 120, 70)
WOOD_DARK   = (100, 70, 30)
WATER_BLUE  = (50, 150, 255)
WATER_LIGHT = (150, 220, 255)

# ==================== HIDDEN PICTURES ====================
def draw_cat_scene(surface):
    """A cute cat in a sunny garden."""
    # Sky gradient
    for y in range(HEIGHT):
        t = y / HEIGHT
        r = int(135 + (180-135)*t)
        g = int(206 + (220-206)*t)
        b = int(235 + (255-235)*t)
        pygame.draw.line(surface, (r,g,b), (0,y), (WIDTH,y))
    # Sun
    pygame.draw.circle(surface, SUN_YELLOW, (680, 90), 50)
    # Clouds
    for cx, cy in [(120,70), (400,50)]:
        pygame.draw.ellipse(surface, WHITE, (cx-40,cy-15,80,30))
        pygame.draw.ellipse(surface, WHITE, (cx-20,cy-25,60,40))
    # Grass
    pygame.draw.rect(surface, GRASS_GREEN, (0, 420, WIDTH, 180))
    # Flowers
    for fx, fy in [(100,480),(280,450),(600,500),(720,440)]:
        pygame.draw.circle(surface, (255,100,120), (fx,fy), 12)
        pygame.draw.circle(surface, (255,255,0), (fx,fy), 5)
        pygame.draw.line(surface, (0,100,0), (fx,fy+12), (fx,fy+35), 3)
    # Cat body
    cat_x, cat_y = 400, 380
    # Tail
    pygame.draw.arc(surface, (255,180,100), (cat_x+30,cat_y-20,60,80), 0, math.pi/2, 8)
    # Body
    pygame.draw.ellipse(surface, (255,180,100), (cat_x-50, cat_y-80, 100, 130))
    # Head
    pygame.draw.circle(surface, (255,180,100), (cat_x, cat_y-110), 50)
    # Ears
    pygame.draw.polygon(surface, (255,180,100), [(cat_x-40,cat_y-140),(cat_x-55,cat_y-180),(cat_x-15,cat_y-130)])
    pygame.draw.polygon(surface, (255,180,100), [(cat_x+40,cat_y-140),(cat_x+55,cat_y-180),(cat_x+15,cat_y-130)])
    # Inner ears
    pygame.draw.polygon(surface, (255,150,180), [(cat_x-38,cat_y-142),(cat_x-50,cat_y-172),(cat_x-20,cat_y-132)])
    pygame.draw.polygon(surface, (255,150,180), [(cat_x+38,cat_y-142),(cat_x+50,cat_y-172),(cat_x+20,cat_y-132)])
    # Eyes
    pygame.draw.ellipse(surface, WHITE, (cat_x-30,cat_y-130,25,35))
    pygame.draw.ellipse(surface, WHITE, (cat_x+5,cat_y-130,25,35))
    pygame.draw.circle(surface, (50,180,50), (cat_x-17,cat_y-115), 10)
    pygame.draw.circle(surface, (50,180,50), (cat_x+17,cat_y-115), 10)
    pygame.draw.circle(surface, BLACK, (cat_x-17,cat_y-115), 5)
    pygame.draw.circle(surface, BLACK, (cat_x+17,cat_y-115), 5)
    # Nose
    pygame.draw.polygon(surface, (255,150,180), [(cat_x,cat_y-105),(cat_x-7,cat_y-98),(cat_x+7,cat_y-98)])
    # Mouth
    pygame.draw.arc(surface, BLACK, (cat_x-12,cat_y-90,24,15), 0, math.pi, 2)
    # Whiskers
    for dx in [-1,1]:
        for dy in [-4,4]:
            pygame.draw.line(surface, BLACK, (cat_x+dx*15,cat_y-100+dy), (cat_x+dx*45,cat_y-110+dy*3), 1)

def draw_house_scene(surface):
    """A cozy house with trees."""
    # Sky
    for y in range(HEIGHT):
        t = y / HEIGHT
        r = int(100 + (150-100)*t)
        g = int(150 + (200-150)*t)
        b = int(220 + (255-220)*t)
        pygame.draw.line(surface, (r,g,b), (0,y), (WIDTH,y))
    # Sun
    pygame.draw.circle(surface, (255,220,100), (700, 80), 45)
    # Mountains
    pygame.draw.polygon(surface, (80,120,80), [(0,400),(200,200),(400,400)])
    pygame.draw.polygon(surface, (60,100,60), [(300,400),(500,220),(700,400)])
    # Grass
    pygame.draw.rect(surface, (100,160,80), (0, 400, WIDTH, 200))
    # House
    house_x, house_y = 350, 280
    pygame.draw.rect(surface, (220,180,120), (house_x, house_y, 120, 120))  # walls
    pygame.draw.polygon(surface, (180,60,60), [(house_x-15,house_y),(house_x+60,house_y-60),(house_x+135,house_y)])  # roof
    pygame.draw.rect(surface, (139,69,19), (house_x+50, house_y+70, 20, 50))  # door
    pygame.draw.circle(surface, (255,200,0), (house_x+65, house_y+95), 4)  # doorknob
    # Windows
    for wx in [house_x+15, house_x+85]:
        pygame.draw.rect(surface, (173,216,230), (wx, house_y+20, 25, 25))
        pygame.draw.line(surface, BLACK, (wx, house_y+32), (wx+25, house_y+32), 1)
        pygame.draw.line(surface, BLACK, (wx+12, house_y+20), (wx+12, house_y+45), 1)
    # Tree
    pygame.draw.rect(surface, (101,67,33), (150, 340, 20, 60))
    pygame.draw.circle(surface, (34,120,15), (160, 310), 40)
    pygame.draw.circle(surface, (34,100,10), (145, 330), 35)

def draw_flower_scene(surface):
    """A vibrant flower field."""
    # Sky
    for y in range(HEIGHT):
        t = y / HEIGHT
        r = int(255 - 30*t)
        g = int(200 + 40*t)
        b = int(200 + 40*t)
        pygame.draw.line(surface, (r,g,b), (0,y), (WIDTH,y))
    # Grass
    pygame.draw.rect(surface, (130,210,90), (0, 350, WIDTH, 250))
    # Stems and flowers
    random.seed(42)  # fixed seed for consistent scene
    for i in range(20):
        fx = random.randint(20, WIDTH-20)
        fy = random.randint(380, 550)
        color = random.choice([(255,100,100),(255,255,100),(255,150,200),(255,200,100)])
        pygame.draw.line(surface, (0,130,0), (fx,fy), (fx,fy-40), 3)
        pygame.draw.circle(surface, color, (fx,fy-40), 15)
        pygame.draw.circle(surface, (255,255,0), (fx,fy-40), 5)
    # Butterflies
    for _ in range(4):
        bx = random.randint(50,750)
        by = random.randint(100,300)
        pygame.draw.circle(surface, (255,150,200), (bx,by), 6)
        pygame.draw.circle(surface, (200,100,255), (bx+8,by-4), 5)
    # Sun
    pygame.draw.circle(surface, (255,240,100), (100, 80), 40)

# ==================== CREATE DIRT SURFACE ====================
def create_dirt_surface(level):
    """Creates a dirty window overlay. Higher level = denser dirt."""
    dirt = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
    dirt.fill((*BLACK, 255))  # fully opaque base

    # Large splotches
    for _ in range(100 + level*20):
        x = random.randint(0, WIDTH)
        y = random.randint(0, HEIGHT)
        r = random.randint(30, 90)
        alpha = random.randint(180, 240)
        dirt_color = (50, 35, 25, alpha)
        pygame.draw.circle(dirt, dirt_color, (x, y), r)

    # Small spots
    for _ in range(400 + level*100):
        x = random.randint(0, WIDTH)
        y = random.randint(0, HEIGHT)
        r = random.randint(3, 12)
        alpha = random.randint(200, 255)
        dirt_color = (40+random.randint(0,30), 25+random.randint(0,20), 15+random.randint(0,20), alpha)
        pygame.draw.circle(dirt, dirt_color, (x, y), r)

    # Streaks
    for _ in range(20 + level*5):
        x1 = random.randint(0, WIDTH)
        y1 = random.randint(0, HEIGHT)
        x2 = x1 + random.randint(-120, 120)
        y2 = y1 + random.randint(-120, 120)
        pygame.draw.line(dirt, (70, 55, 40, 120), (x1, y1), (x2, y2), random.randint(4, 12))

    return dirt

# ==================== WATER PARTICLE ====================
class WaterParticle:
    def __init__(self, x, y, angle, speed):
        self.x = x
        self.y = y
        self.vx = math.cos(angle) * speed + random.uniform(-1.2, 1.2)
        self.vy = math.sin(angle) * speed + random.uniform(-1.2, 1.2)
        self.life = random.randint(12, 28)
        self.max_life = self.life

    def update(self):
        self.x += self.vx
        self.y += self.vy
        self.vy += 0.2
        self.life -= 1
        return self.life > 0

    def draw(self, surface):
        alpha = int(200 * (self.life / self.max_life))
        radius = max(1, int(4 * self.life / self.max_life))
        if radius > 0:
            s = pygame.Surface((radius*2, radius*2), pygame.SRCALPHA)
            pygame.draw.circle(s, (150, 210, 255, alpha), (radius, radius), radius)
            surface.blit(s, (self.x - radius, self.y - radius))

# ==================== GAME CLASS ====================
class CleanMaster:
    def __init__(self):
        self.levels = [draw_cat_scene, draw_house_scene, draw_flower_scene]
        self.current_level = 0
        self.hidden_image = pygame.Surface((WIDTH, HEIGHT))
        self.particles = []            # ★ moved before load_level()
        self.cleaning = False
        self.nozzle_x, self.nozzle_y = WIDTH//2, HEIGHT//2
        self.score = 0
        self.progress = 0.0
        self.level_complete = False
        self.font_big = pygame.font.Font(None, 60)
        self.font_med = pygame.font.Font(None, 36)
        self.font_small = pygame.font.Font(None, 24)
        self.eraser_radius = 30
        self.load_level()             # now safe, particles already exists

    def load_level(self):
        """Prepare the next level: new hidden picture and dirt."""
        self.hidden_image.fill((0,0,0))
        self.levels[self.current_level](self.hidden_image)
        self.dirt_surface = create_dirt_surface(self.current_level + 1)
        self.progress = 0.0
        self.level_complete = False
        self.score = 0
        self.particles.clear()

    def handle_events(self):
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit(); sys.exit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    pygame.quit(); sys.exit()
                if event.key == pygame.K_SPACE and self.level_complete:
                    self.current_level = (self.current_level + 1) % len(self.levels)
                    self.load_level()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    self.cleaning = True
            if event.type == pygame.MOUSEBUTTONUP:
                if event.button == 1:
                    self.cleaning = False

        self.nozzle_x, self.nozzle_y = pygame.mouse.get_pos()

    def update(self):
        if self.level_complete:
            return

        if self.cleaning:
            eraser = pygame.Surface((self.eraser_radius*2, self.eraser_radius*2), pygame.SRCALPHA)
            pygame.draw.circle(eraser, (0,0,0,0), (self.eraser_radius, self.eraser_radius), self.eraser_radius)
            self.dirt_surface.blit(eraser, (self.nozzle_x - self.eraser_radius, self.nozzle_y - self.eraser_radius),
                                   special_flags=pygame.BLEND_RGBA_MIN)

            spray_angle = random.uniform(-math.pi/2 - 0.5, -math.pi/2 + 0.5)
            for _ in range(5):
                self.particles.append(WaterParticle(self.nozzle_x, self.nozzle_y+10, spray_angle, random.uniform(3, 8)))
            self.score += 1

        self.particles = [p for p in self.particles if p.update()]

        # Calculate progress
        transparent = 0
        sample = 1500
        for _ in range(sample):
            x = random.randint(0, WIDTH-1)
            y = random.randint(0, HEIGHT-1)
            if self.dirt_surface.get_at((x, y)).a < 15:
                transparent += 1
        self.progress = transparent / sample

        if self.progress >= 0.97:
            self.level_complete = True

    def draw(self):
        screen.blit(self.hidden_image, (0,0))
        screen.blit(self.dirt_surface, (0,0))
        for p in self.particles:
            p.draw(screen)

        # Wooden frame
        frame = 15
        pygame.draw.rect(screen, WOOD_LIGHT, (0,0,WIDTH,frame))
        pygame.draw.rect(screen, WOOD_DARK, (0,0,WIDTH,frame//2))
        pygame.draw.rect(screen, WOOD_LIGHT, (0,0,frame,HEIGHT))
        pygame.draw.rect(screen, WOOD_DARK, (0,0,frame//2,HEIGHT))
        pygame.draw.rect(screen, WOOD_LIGHT, (0,HEIGHT-frame,WIDTH,frame))
        pygame.draw.rect(screen, WOOD_DARK, (0,HEIGHT-frame//2,WIDTH,frame//2))
        pygame.draw.rect(screen, WOOD_LIGHT, (WIDTH-frame,0,frame,HEIGHT))
        pygame.draw.rect(screen, WOOD_DARK, (WIDTH-frame//2,0,frame//2,HEIGHT))

        # Spray nozzle
        pygame.draw.circle(screen, (50,50,50), (self.nozzle_x, self.nozzle_y), 15)
        pygame.draw.circle(screen, (130,130,130), (self.nozzle_x-3, self.nozzle_y-3), 9)
        tip_x = self.nozzle_x
        tip_y = self.nozzle_y + 20
        pygame.draw.line(screen, (180,180,180), (self.nozzle_x, self.nozzle_y), (tip_x, tip_y), 5)
        if self.cleaning:
            spray_pts = [(tip_x + random.uniform(-5,5), tip_y + random.uniform(0,12)) for _ in range(6)]
            pygame.draw.lines(screen, WATER_LIGHT, False, spray_pts, 2)

        # UI
        self.draw_ui()

        # Level complete overlay
        if self.level_complete:
            overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
            overlay.fill((0,0,0,160))
            screen.blit(overlay, (0,0))
            win_text = self.font_big.render("CLEAN!", True, (255,255,100))
            screen.blit(win_text, (WIDTH//2-100, HEIGHT//2-60))
            prompt = self.font_med.render("Press SPACE for next level", True, WHITE)
            screen.blit(prompt, (WIDTH//2-180, HEIGHT//2+20))

        pygame.display.flip()

    def draw_ui(self):
        # Progress bar
        bx, by, bw, bh = 30, 30, 260, 28
        pygame.draw.rect(screen, (60,60,60), (bx, by, bw, bh))
        pygame.draw.rect(screen, (200,200,200), (bx, by, bw, bh), 2)
        fill_w = int(bw * self.progress)
        if fill_w > 0:
            color = (100, int(200*self.progress), 50)
            pygame.draw.rect(screen, color, (bx, by, fill_w, bh))
        pct_text = self.font_small.render(f"{int(self.progress*100)}%", True, WHITE)
        screen.blit(pct_text, (bx+bw//2-25, by+4))

        # Level & score
        level_text = self.font_med.render(f"Level {self.current_level+1}", True, WHITE)
        screen.blit(level_text, (WIDTH-180, 30))
        score_text = self.font_small.render(f"Score: {self.score}", True, WHITE)
        screen.blit(score_text, (WIDTH-180, 60))

        # Instruction
        instr = self.font_small.render("Hold LEFT MOUSE to spray", True, WHITE)
        screen.blit(instr, (30, HEIGHT-30))

    def run(self):
        while True:
            self.handle_events()
            self.update()
            self.draw()
            clock.tick(FPS)

if __name__ == "__main__":
    game = CleanMaster()
    game.run()