import pygame
import random
import math
import sys

# Initialize
pygame.init()

# Window
WIDTH, HEIGHT = 900, 650
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Cartoon Zombie Shooter")

# Colors (bright cartoon palette)
SKY_BLUE = (135, 206, 235)
GRASS_GREEN = (124, 252, 0)
DARK_GRASS = (34, 139, 34)
DARK_GREEN = (0, 100, 0)
YELLOW = (255, 255, 0)
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 50, 50)
ORANGE = (255, 165, 0)
BROWN = (139, 69, 19)
LIGHT_BROWN = (160, 130, 90)
PINK = (255, 182, 193)
GRAY = (128, 128, 128)
DARK_GRAY = (64, 64, 64)
SKIN = (255, 224, 189)
BLUE = (70, 130, 180)
DARK_BLUE = (0, 0, 139)

# Clock
clock = pygame.time.Clock()
FPS = 60

# Fonts
font = pygame.font.Font(None, 36)
big_font = pygame.font.Font(None, 72)

# Player
PLAYER_SPEED = 5
PLAYER_RADIUS = 20
player_x = WIDTH // 2
player_y = HEIGHT // 2
player_health = 5
max_health = 5

# Shooting
SHOOT_COOLDOWN = 12
shoot_timer = 0
bullets = []

# Zombies
ZOMBIE_SPEED = 2
ZOMBIE_RADIUS = 16
zombies = []
zombie_spawn_timer = 0
SPAWN_DELAY = 40

# Particles
particles = []

# Score
score = 0
game_over = False

# Decorations (trees, flowers, rocks)
decorations = []

def init_decorations():
    global decorations
    decorations = []
    # Trees
    for _ in range(10):
        x = random.randint(40, WIDTH - 40)
        y = random.randint(50, HEIGHT - 50)
        decorations.append(('tree', x, y))
    # Flowers
    for _ in range(20):
        x = random.randint(20, WIDTH - 20)
        y = random.randint(20, HEIGHT - 20)
        decorations.append(('flower', x, y))
    # Rocks
    for _ in range(8):
        x = random.randint(30, WIDTH - 30)
        y = random.randint(30, HEIGHT - 30)
        decorations.append(('rock', x, y))

init_decorations()

def spawn_zombie():
    side = random.randint(0, 3)
    if side == 0:
        x = random.randint(0, WIDTH)
        y = -ZOMBIE_RADIUS
    elif side == 1:
        x = WIDTH + ZOMBIE_RADIUS
        y = random.randint(0, HEIGHT)
    elif side == 2:
        x = random.randint(0, WIDTH)
        y = HEIGHT + ZOMBIE_RADIUS
    else:
        x = -ZOMBIE_RADIUS
        y = random.randint(0, HEIGHT)
    zombies.append([x, y, 1])

def spawn_particles(x, y, color, count=8):
    for _ in range(count):
        angle = random.uniform(0, 2 * math.pi)
        speed = random.uniform(1, 4)
        dx = math.cos(angle) * speed
        dy = math.sin(angle) * speed
        particles.append([x, y, dx, dy, 15, color])

def restart_game():
    global player_x, player_y, player_health, zombies, bullets, score, game_over, shoot_timer, particles
    player_x = WIDTH // 2
    player_y = HEIGHT // 2
    player_health = max_health
    zombies.clear()
    bullets.clear()
    particles.clear()
    score = 0
    game_over = False
    shoot_timer = 0
    init_decorations()

# ---------- Drawing functions (cartoon style) ----------
def draw_background():
    screen.fill(SKY_BLUE)
    pygame.draw.rect(screen, GRASS_GREEN, (0, HEIGHT-100, WIDTH, 100))
    # Distant hills
    for i in range(5):
        px = random.randint(0, WIDTH)
        pygame.draw.circle(screen, DARK_GRASS, (px, HEIGHT-100), random.randint(40, 80))

    for deco in decorations:
        typ, dx, dy = deco
        if typ == 'tree':
            pygame.draw.rect(screen, BROWN, (dx-6, dy, 12, 40))
            pygame.draw.circle(screen, DARK_GREEN, (dx, dy-20), 22)
            pygame.draw.circle(screen, DARK_GREEN, (dx-15, dy-10), 18)
            pygame.draw.circle(screen, DARK_GREEN, (dx+15, dy-10), 18)
            pygame.draw.circle(screen, (100, 200, 100), (dx-5, dy-25), 6)
        elif typ == 'flower':
            pygame.draw.line(screen, DARK_GREEN, (dx, dy), (dx, dy-12), 2)
            for angle in range(0, 360, 45):
                rad = math.radians(angle)
                px = dx + math.cos(rad)*6
                py = dy-12 + math.sin(rad)*6
                pygame.draw.circle(screen, random.choice([RED, YELLOW, PINK, WHITE]), (int(px), int(py)), 4)
            pygame.draw.circle(screen, ORANGE, (dx, dy-12), 4)
        elif typ == 'rock':
            pygame.draw.ellipse(screen, GRAY, (dx-8, dy-4, 16, 8))
            pygame.draw.ellipse(screen, DARK_GRAY, (dx-6, dy-3, 12, 6))

def draw_player(x, y):
    # Shadow
    pygame.draw.circle(screen, (0,0,0,30), (x+2, y+2), PLAYER_RADIUS)
    # Body
    pygame.draw.circle(screen, BLUE, (x, y), PLAYER_RADIUS)
    pygame.draw.circle(screen, DARK_BLUE, (x, y), PLAYER_RADIUS, 3)
    # Head
    head_radius = 12
    pygame.draw.circle(screen, SKIN, (x, y-18), head_radius)
    # Hat
    pygame.draw.ellipse(screen, RED, (x-14, y-34, 28, 12))
    pygame.draw.rect(screen, RED, (x-10, y-32, 20, 8))
    # Eyes (look toward mouse)
    eye_angle = math.atan2(pygame.mouse.get_pos()[1]-y, pygame.mouse.get_pos()[0]-x)
    ex = 4 * math.cos(eye_angle)
    ey = 4 * math.sin(eye_angle)
    pygame.draw.circle(screen, WHITE, (x+ex-3, y-22+ey), 4)
    pygame.draw.circle(screen, BLACK, (x+ex-3, y-22+ey), 2)
    pygame.draw.circle(screen, WHITE, (x+ex+3, y-22+ey), 4)
    pygame.draw.circle(screen, BLACK, (x+ex+3, y-22+ey), 2)
    # Gun
    gun_end = (x + 26 * math.cos(eye_angle), y + 26 * math.sin(eye_angle))
    pygame.draw.line(screen, BLACK, (x, y), gun_end, 6)
    pygame.draw.line(screen, GRAY, (x, y), gun_end, 3)

def draw_zombie(zx, zy, frame):
    sway = math.sin(frame * 0.2) * 3
    body_color = (100, 180, 100)
    pygame.draw.circle(screen, body_color, (int(zx+sway), zy), ZOMBIE_RADIUS)
    pygame.draw.circle(screen, (50, 130, 50), (int(zx+sway), zy), ZOMBIE_RADIUS, 3)
    # Ragged clothes
    pygame.draw.arc(screen, BROWN, (zx-12+sway, zy-8, 24, 16), 0, 3.14, 3)
    # Eyes
    eye_x = int(zx+sway)
    pygame.draw.circle(screen, WHITE, (eye_x-5, zy-6), 5)
    pygame.draw.circle(screen, BLACK, (eye_x-4, zy-6), 2)
    pygame.draw.circle(screen, WHITE, (eye_x+5, zy-6), 5)
    pygame.draw.circle(screen, BLACK, (eye_x+6, zy-6), 2)
    # Mouth
    mouth_rect = (eye_x-6, zy, 12, 8)
    pygame.draw.arc(screen, BLACK, mouth_rect, 0, 3.14, 2)
    # Random blood drops
    if random.random() < 0.3:
        pygame.draw.circle(screen, RED, (eye_x+random.randint(-6,6), zy+random.randint(2,6)), 2)

def draw_bullet(bx, by):
    pygame.draw.circle(screen, YELLOW, (int(bx), int(by)), 5)
    pygame.draw.circle(screen, WHITE, (int(bx), int(by)), 2)

def update_and_draw_particles():
    for p in particles[:]:
        p[0] += p[2]
        p[1] += p[3]
        p[4] -= 1
        if p[4] <= 0:
            particles.remove(p)
            continue
        fade = p[4] / 15
        color = tuple(int(c * fade) for c in p[5])
        pygame.draw.circle(screen, color, (int(p[0]), int(p[1])), 3)

# Main loop
frame_count = 0
running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_r and game_over:
                restart_game()

    if not game_over:
        # Movement
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            player_x -= PLAYER_SPEED
        if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            player_x += PLAYER_SPEED
        if keys[pygame.K_UP] or keys[pygame.K_w]:
            player_y -= PLAYER_SPEED
        if keys[pygame.K_DOWN] or keys[pygame.K_s]:
            player_y += PLAYER_SPEED
        player_x = max(PLAYER_RADIUS, min(WIDTH - PLAYER_RADIUS, player_x))
        player_y = max(PLAYER_RADIUS, min(HEIGHT - PLAYER_RADIUS, player_y))

        # Shooting
        mouse_pressed = pygame.mouse.get_pressed()
        if mouse_pressed[0] and shoot_timer <= 0:
            mx, my = pygame.mouse.get_pos()
            angle = math.atan2(my - player_y, mx - player_x)
            bullets.append([player_x, player_y, angle])
            shoot_timer = SHOOT_COOLDOWN
        if shoot_timer > 0:
            shoot_timer -= 1

        # Bullets movement
        for bullet in bullets[:]:
            bullet[0] += 10 * math.cos(bullet[2])
            bullet[1] += 10 * math.sin(bullet[2])
            if bullet[0] < 0 or bullet[0] > WIDTH or bullet[1] < 0 or bullet[1] > HEIGHT:
                bullets.remove(bullet)

        # Zombie spawning
        zombie_spawn_timer += 1
        if zombie_spawn_timer >= SPAWN_DELAY:
            spawn_zombie()
            zombie_spawn_timer = 0
            SPAWN_DELAY = max(10, 40 - score // 5)

        # Zombie movement + collision with player
        for zombie in zombies[:]:
            dx = player_x - zombie[0]
            dy = player_y - zombie[1]
            dist = math.hypot(dx, dy)
            if dist != 0:
                dx /= dist
                dy /= dist
            zombie[0] += dx * ZOMBIE_SPEED
            zombie[1] += dy * ZOMBIE_SPEED

            if math.hypot(player_x - zombie[0], player_y - zombie[1]) < PLAYER_RADIUS + ZOMBIE_RADIUS:
                player_health -= 1
                spawn_particles(zombie[0], zombie[1], RED, 12)
                zombies.remove(zombie)
                if player_health <= 0:
                    game_over = True
                continue

        # Bullet-zombie collision
        for bullet in bullets[:]:
            hit = False
            for zombie in zombies[:]:
                if math.hypot(bullet[0] - zombie[0], bullet[1] - zombie[1]) < ZOMBIE_RADIUS + 6:
                    spawn_particles(zombie[0], zombie[1], ORANGE, 15)
                    zombies.remove(zombie)
                    hit = True
                    score += 1
                    break
            if hit:
                bullets.remove(bullet)

    # Drawing
    draw_background()
    update_and_draw_particles()

    for zombie in zombies:
        draw_zombie(zombie[0], zombie[1], frame_count)

    for bullet in bullets:
        draw_bullet(bullet[0], bullet[1])

    draw_player(player_x, player_y)

    # UI (now all in English)
    bar_width = 200
    bar_height = 20
    pygame.draw.rect(screen, (100,100,100), (20, 20, bar_width, bar_height))
    health_width = int(bar_width * (player_health / max_health))
    pygame.draw.rect(screen, RED, (20, 20, health_width, bar_height))
    pygame.draw.rect(screen, BLACK, (20, 20, bar_width, bar_height), 3)
    health_label = font.render("HP", True, RED)  # Short and simple
    screen.blit(health_label, (20, 45))

    # Score
    score_surf = font.render(f"Kills: {score}", True, BLACK)
    screen.blit(score_surf, (WIDTH - 180, 20))

    # Controls tip
    tip = font.render("WASD/Arrows: Move | Mouse: Shoot | R: Restart", True, DARK_BLUE)
    screen.blit(tip, (WIDTH//2 - tip.get_width()//2, HEIGHT - 40))

    # Game over screen
    if game_over:
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((255, 255, 255, 150))
        screen.blit(overlay, (0, 0))
        go_text = big_font.render("GAME OVER", True, RED)
        restart_text = font.render("Press R to Restart", True, BLACK)
        screen.blit(go_text, (WIDTH//2 - go_text.get_width()//2, HEIGHT//2 - 60))
        screen.blit(restart_text, (WIDTH//2 - restart_text.get_width()//2, HEIGHT//2 + 20))

    pygame.display.flip()
    clock.tick(FPS)
    frame_count += 1

pygame.quit()
sys.exit()