import pygame
import math
import random

# --- КОНСТАНТЫ ГЛОБАЛЬНОЙ НАСТРОЙКИ ---
WIDTH, HEIGHT = 1000, 700
FPS = 60
TILE_SIZE = 50
GRAVITY = 0.8
FRICTION = 0.94

# ЦВЕТА
WHITE = (255, 255, 255)
BLACK = (15, 15, 25)
RED = (235, 50, 50)
SKY = (100, 160, 230)
DIRT = (100, 65, 45)
GRASS = (60, 170, 60)
GOLD = (255, 215, 0)
LAVA = (255, 80, 0)


# --- ВСПОМОГАТЕЛЬНЫЕ КЛАССЫ (ЧАСТИЦЫ) ---
class Particle:
    def __init__(self, x, y, color):
        self.x, self.y = x, y
        self.color = color
        self.vx = random.uniform(-3, 3)
        self.vy = random.uniform(-3, 3)
        self.life = 255
        self.size = random.randint(3, 6)

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

    def draw(self, screen, scroll):
        if self.life > 0:
            surf = pygame.Surface((self.size, self.size))
            surf.set_alpha(self.life)
            surf.fill(self.color)
            screen.blit(surf, (self.x - scroll[0], self.y - scroll[1]))


# --- ОСНОВНЫЕ ИГРОВЫЕ ОБЪЕКТЫ ---
class Player(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.radius = 22
        self.image = pygame.Surface((self.radius * 2, self.radius * 2), pygame.SRCALPHA)
        self.rect = self.image.get_rect(center=(x, y))
        self.pos = pygame.Vector2(x, y)
        self.vel = pygame.Vector2(0, 0)
        self.angle = 0
        self.on_ground = False
        self.is_dead = False
        self.score = 0

    def draw_ball(self):
        self.image.fill((0, 0, 0, 0))
        # Основное тело
        pygame.draw.circle(self.image, RED, (self.radius, self.radius), self.radius)
        # Глаза (вращаются вместе с шаром)
        eye_x = self.radius + math.cos(math.radians(self.angle)) * 10
        eye_y = self.radius + math.sin(math.radians(self.angle)) * 10
        pygame.draw.circle(self.image, WHITE, (int(eye_x), int(eye_y)), 5)

    def apply_physics(self, platforms):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]: self.vel.x -= 0.8
        if keys[pygame.K_RIGHT]: self.vel.x += 0.8

        if (keys[pygame.K_SPACE] or keys[pygame.K_UP]) and self.on_ground:
            self.vel.y = -17
            self.on_ground = False

        self.vel.x *= FRICTION
        self.vel.y += GRAVITY

        # Движение по X
        self.pos.x += self.vel.x
        self.rect.centerx = self.pos.x
        self.check_collision(platforms, 'x')

        # Движение по Y
        self.pos.y += self.vel.y
        self.rect.centery = self.pos.y
        self.check_collision(platforms, 'y')

        # Визуальное вращение
        self.angle += self.vel.x * 2
        self.draw_ball()

    def check_collision(self, platforms, direction):
        for plat in platforms:
            if self.rect.colliderect(plat.rect):
                if direction == 'x':
                    if self.vel.x > 0: self.rect.right = plat.rect.left
                    if self.vel.x < 0: self.rect.left = plat.rect.right
                    self.pos.x = self.rect.centerx
                    self.vel.x = 0
                else:
                    if self.vel.y > 0:
                        self.rect.bottom = plat.rect.top
                        self.on_ground = True
                        self.vel.y = 0
                    if self.vel.y < 0:
                        self.rect.top = plat.rect.bottom
                        self.vel.y = 0
                    self.pos.y = self.rect.centery


class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y, walk_dist):
        super().__init__()
        self.image = pygame.Surface((45, 45))
        self.image.fill(BLACK)
        pygame.draw.rect(self.image, RED, (5, 5, 35, 10))  # Злая бровь
        self.rect = self.image.get_rect(topleft=(x, y))
        self.start_x = x
        self.dist = walk_dist
        self.speed = 3

    def update(self):
        self.rect.x += self.speed
        if abs(self.rect.x - self.start_x) >= self.dist:
            self.speed *= -1


class Trampoline(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = pygame.Surface((50, 20))
        self.image.fill((200, 200, 0))
        self.rect = self.image.get_rect(topleft=(x, y + 30))


# --- КЛАСС ДВИЖКА ИГРЫ ---
class RedBallEngine:
    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
        pygame.display.set_caption("Red Ball 4: Python Mega Edition")
        self.clock = pygame.time.Clock()
        self.font = pygame.font.SysFont("Verdana", 24, bold=True)
        self.state = "MENU"
        self.particles = []
        self.current_lvl = 0
        self.scroll = [0, 0]
        self.init_levels()

    def init_levels(self):
        # Карта символов: G=Пол, P=Игрок, E=Враг, T=Батут, C=Монета, F=Финиш, S=Шипы
        self.level_maps = [
            [
                "                                                ",
                "                                                ",
                "       C    C    C                              ",
                "      GGG  GGG  GGG                             ",
                "                                                ",
                " P      E       T        G   G   G      F       ",
                "GGGGGGGGGGGGGGGGGGGGGGG  G S G S G  GGGGGGGGGGGG",
            ],
            [
                " P                                              ",
                " G                        GGGGGG                ",
                "  G    C    E    C     G                        ",
                "   G  GGG  GGG  GGG   G G      E       F        ",
                "    G CCCCCCCCCCCCCC G   G   GGGGG   GGGGGG     ",
                "     G CCCCCCCCCCC  G     G                     ",
                "      GGGGGGGGGGGGGG       GGGGGGGGGGGGGGGGGGGGG",
            ],
            [
                " P                                              ",
                " G                                              ",
                "  G    C    E    C                              ",
                "   G  GGG  GGG  GGG   G G      E       F        ",
                "    G                G   G   GGGGG   GGGGGG     ",
                "     G     T        G     G                     ",
                "      GGGGGGGGGGGGGG       GGGGGGGGGGGGGGGGGGGGG",
            ]



        ]

    def setup_level(self, idx):
        self.all_sprites = pygame.sprite.Group()
        self.platforms = pygame.sprite.Group()
        self.enemies = pygame.sprite.Group()
        self.trampolines = pygame.sprite.Group()
        self.coins = pygame.sprite.Group()
        self.spikes = []

        raw_map = self.level_maps[idx]
        for r, row in enumerate(raw_map):
            for c, tile in enumerate(row):
                x, y = c * TILE_SIZE, r * TILE_SIZE + 300
                if tile == "G":
                    p = pygame.sprite.Sprite()
                    p.image = pygame.Surface((TILE_SIZE, TILE_SIZE))
                    p.image.fill(DIRT)
                    pygame.draw.rect(p.image, GRASS, (0, 0, TILE_SIZE, 10))
                    p.rect = p.image.get_rect(topleft=(x, y))
                    self.platforms.add(p)
                elif tile == "P":
                    self.player = Player(x, y)
                elif tile == "E":
                    en = Enemy(x, y, 150)
                    self.enemies.add(en)
                elif tile == "T":
                    t = Trampoline(x, y)
                    self.trampolines.add(t)
                elif tile == "C":
                    coin = pygame.sprite.Sprite()
                    coin.image = pygame.Surface((20, 20), pygame.SRCALPHA)
                    pygame.draw.circle(coin.image, GOLD, (10, 10), 10)
                    coin.rect = coin.image.get_rect(center=(x + 25, y + 25))
                    self.coins.add(coin)
                elif tile == "S":
                    spike = pygame.Rect(x, y + 30, TILE_SIZE, 20)
                    self.spikes.append(spike)
                elif tile == "F":
                    self.finish_rect = pygame.Rect(x, y - 50, 60, 100)

    def draw_parallax(self):
        # Дальние горы (движутся медленно)
        for i in range(-2, 10):
            pygame.draw.polygon(self.screen, (80, 130, 200), [
                (i * 400 - self.scroll[0] * 0.2, HEIGHT),
                (i * 400 + 200 - self.scroll[0] * 0.2, HEIGHT - 300),
                (i * 400 + 400 - self.scroll[0] * 0.2, HEIGHT)
            ])

    def update(self):
        if self.state == "GAME":
            self.player.apply_physics(self.platforms)
            self.enemies.update()

            # Камера
            self.scroll[0] += (self.player.rect.centerx - self.scroll[0] - WIDTH / 2) / 10
            self.scroll[1] += (self.player.rect.centery - self.scroll[1] - HEIGHT / 2) / 10

            # Коллизии
            if pygame.sprite.spritecollide(self.player, self.enemies, False):
                self.death_effect()

            for t in self.trampolines:
                if self.player.rect.colliderect(t.rect):
                    self.player.vel.y = -25

            collected = pygame.sprite.spritecollide(self.player, self.coins, True)
            self.player.score += len(collected)

            for s in self.spikes:
                if self.player.rect.colliderect(s):
                    self.death_effect()

            if self.player.rect.colliderect(self.finish_rect):
                self.state = "WIN"

            if self.player.rect.y > HEIGHT + 500:
                self.setup_level(self.current_lvl)

            # Пыль при движении
            if abs(self.player.vel.x) > 2 and self.player.on_ground:
                if random.random() > 0.7:
                    self.particles.append(Particle(self.player.pos.x, self.player.rect.bottom, WHITE))

    def death_effect(self):
        for _ in range(20):
            self.particles.append(Particle(self.player.pos.x, self.player.pos.y, RED))
        self.setup_level(self.current_lvl)

    def draw(self):
        self.screen.fill(SKY)
        self.draw_parallax()

        if self.state == "GAME":
            # Платформы
            for p in self.platforms:
                self.screen.blit(p.image, (p.rect.x - self.scroll[0], p.rect.y - self.scroll[1]))
            # Шипы
            for s in self.spikes:
                pygame.draw.polygon(self.screen, BLACK, [
                    (s.left - self.scroll[0], s.bottom - self.scroll[1]),
                    (s.right - self.scroll[0], s.bottom - self.scroll[1]),
                    (s.centerx - self.scroll[0], s.top - self.scroll[1])
                ])
            # Враги, Монеты, Игрок
            for e in self.enemies: self.screen.blit(e.image, (e.rect.x - self.scroll[0], e.rect.y - self.scroll[1]))
            for c in self.coins: self.screen.blit(c.image, (c.rect.x - self.scroll[0], c.rect.y - self.scroll[1]))
            for t in self.trampolines: self.screen.blit(t.image, (t.rect.x - self.scroll[0], t.rect.y - self.scroll[1]))

            pygame.draw.rect(self.screen, (50, 200, 50),
                             (self.finish_rect.x - self.scroll[0], self.finish_rect.y - self.scroll[1], 60, 100))
            self.screen.blit(self.player.image,
                             (self.player.rect.x - self.scroll[0], self.player.rect.y - self.scroll[1]))

            # Частицы
            for p in self.particles[:]:
                if not p.update(): self.particles.remove(p)
                p.draw(self.screen, self.scroll)

            # UI
            score_surf = self.font.render(f"SCORE: {self.player.score}", True, WHITE)
            self.screen.blit(score_surf, (20, 20))

        elif self.state == "MENU":
            title = self.font.render("RED BALL PYTHON: MEGA EDITION", True, WHITE)
            hint = self.font.render("PRESS SPACE TO START", True, WHITE)
            self.screen.blit(title, (WIDTH // 2 - 200, HEIGHT // 2 - 50))
            self.screen.blit(hint, (WIDTH // 2 - 150, HEIGHT // 2 + 20))

        elif self.state == "WIN":
            win_txt = self.font.render("LEVEL COMPLETE! PRESS R TO NEXT", True, WHITE)
            self.screen.blit(win_txt, (WIDTH // 2 - 200, HEIGHT // 2))

        pygame.display.flip()

    def main_loop(self):
        while True:
            for event in pygame.event.get():
                if event.type == pygame.QUIT: return
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_SPACE and self.state == "MENU":
                        self.setup_level(0)
                        self.state = "GAME"
                    if event.key == pygame.K_r and self.state == "WIN":
                        self.current_lvl = (self.current_lvl + 1) % len(self.level_maps)
                        self.setup_level(self.current_lvl)
                        self.state = "GAME"

            self.update()
            self.draw()
            self.clock.tick(FPS)


if __name__ == "__main__":
    game = RedBallEngine()
    game.main_loop()