import pygame
import random
import math
from enum import Enum

# 初始化 Pygame
pygame.init()
pygame.mixer.init()

# 屏幕设置
SCREEN_WIDTH = 900
SCREEN_HEIGHT = 600
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("🎭 趣味火柴人世界")
clock = pygame.time.Clock()

# 颜色定义
COLORS = {
    'WHITE': (255, 255, 255),
    'BLACK': (0, 0, 0),
    'RED': (255, 50, 50),
    'GREEN': (50, 200, 100),
    'BLUE': (80, 150, 250),
    'YELLOW': (255, 220, 60),
    'PURPLE': (180, 90, 240),
    'ORANGE': (255, 160, 40),
    'CYAN': (30, 210, 230),
    'DARK_BLUE': (20, 10, 70),
    'SKIN': (255, 215, 170),
    'BROWN': (140, 85, 45),
    'GRAY': (120, 130, 145),
    'GROUND': (35, 55, 75),
}

class GameState(Enum):
    MENU = 1
    PLAYING = 2
    GAME_OVER = 3

class Particle:
    def __init__(self, x, y, color, vx=None, vy=None, life=60, size=4):
        self.x = x
        self.y = y
        self.color = color
        self.vx = vx if vx else random.uniform(-5, 5)
        self.vy = vy if vy else random.uniform(-8, -2)
        self.life = life
        self.max_life = life
        self.size = random.randint(size - 2, size + 2)
        self.gravity = 0.25
        
    def update(self):
        self.x += self.vx
        self.vy += self.gravity
        self.y += self.vy
        self.life -= 1
        return self.life > 0
    
    def draw(self, surface):
        alpha = max(0, int(255 * (self.life / self.max_life)))
        color = (*self.color[:3], alpha) if len(self.color) == 3 else self.color
        radius = max(1, int(self.size * (self.life / self.max_life)))
        pygame.draw.circle(surface, color[:3], (int(self.x), int(self.y)), radius)

class Star:
    def __init__(self):
        self.x = random.randint(0, SCREEN_WIDTH)
        self.y = random.randint(0, SCREEN_HEIGHT // 2)
        self.size = random.uniform(0.5, 2.5)
        self.twinkle_speed = random.uniform(0.02, 0.05)
        self.brightness = random.uniform(0.3, 1.0)
        
    def update(self):
        self.brightness = 0.5 + 0.5 * math.sin(pygame.time.get_ticks() * self.twinkle_speed + self.x)
        
    def draw(self, surface):
        alpha = int(255 * self.brightness)
        color = (alpha, alpha, min(255, alpha + 30))
        pygame.draw.circle(surface, color, (int(self.x), int(self.y)), self.size)

class Mountain:
    def __init__(self, layer):
        self.layer = layer
        self.points = []
        self.color = (
            random.randint(20, 50) + layer * 15,
            random.randint(15, 40) + layer * 12,
            random.randint(40, 65) + layer * 18
        )
        self.generate()
        
    def generate(self):
        self.points = [(0, SCREEN_HEIGHT)]
        x = 0
        while x < SCREEN_WIDTH + 400:
            height = random.randint(80, 200) + self.layer * 30
            self.points.append((x, SCREEN_HEIGHT - height - 100))
            x += random.randint(60, 150) + self.layer * 20
        self.points.append((SCREEN_WIDTH + 500, SCREEN_HEIGHT))

class Obstacle:
    def __init__(self, x, type_id=None):
        self.x = x
        self.type = type_id if type_id else random.choice(['spike', 'box', 'saw'])
        self.width = 40
        self.height = 40
        self.y = SCREEN_HEIGHT - 110 - self.height
        self.passed = False
        self.rotation = 0
        
    def update(self, speed):
        self.x -= speed
        self.rotation += 0.03
        
    def draw(self, surface):
        rect = pygame.Rect(self.x, self.y, self.width, self.height)
        
        if self.type == 'spike':
            points = [
                (rect.centerx, rect.top),
                (rect.left, rect.bottom),
                (rect.right, rect.bottom)
            ]
            pygame.draw.polygon(surface, COLORS['RED'], points)
            pygame.draw.polygon(surface, COLORS['YELLOW'], points, 2)
            
        elif self.type == 'box':
            pygame.draw.rect(surface, COLORS['BROWN'], rect)
            pygame.draw.rect(surface, COLORS['YELLOW'], rect, 3)
            # X mark
            pygame.draw.line(surface, COLORS['YELLOW'], rect.topleft, rect.bottomright, 2)
            pygame.draw.line(surface, COLORS['YELLOW'], rect.topright, rect.bottomleft, 2)
            
        elif self.type == 'saw':
            center = rect.center
            radius = self.width // 2
            teeth = 8
            points = []
            for i in range(teeth * 2):
                angle = self.rotation + math.pi * i / teeth
                r = radius if i % 2 == 0 else radius * 0.6
                points.append((
                    center[0] + r * math.cos(angle),
                    center[1] + r * math.sin(angle)
                ))
            pygame.draw.polygon(surface, COLORS['GRAY'], points)
            pygame.draw.polygon(surface, COLORS['CYAN'], points, 2)
            pygame.draw.circle(surface, COLORS['YELLOW'], center, 5)

class StickMan:
    def __init__(self, x, y):
        self.x = x
        self.y = y
        self.base_y = y
        self.velocity_x = 0
        self.velocity_y = 0
        self.on_ground = True
        self.facing_right = True
        self.action = "idle"
        self.action_timer = 0
        self.invincible = False
        self.invincible_timer = 0
        self.combo = 0
        self.combo_timer = 0
        self.walk_frame = 0
        
        # 身体参数
        self.head_radius = 14
        self.body_length = 35
        self.arm_length = 22
        self.leg_length = 28
        
    def update(self, keys, mouse_pos, mouse_clicked):
        # 水平移动
        if keys[pygame.K_LEFT] or keys[pygame.K_a]:
            self.velocity_x = -5
            self.facing_right = False
            if self.on_ground and self.action not in ['jump', 'kick']:
                self.action = "walk"
        elif keys[pygame.K_RIGHT] or keys[pygame.K_d]:
            self.velocity_x = 5
            self.facing_right = True
            if self.on_ground and self.action not in ['jump', 'kick']:
                self.action = "walk"
        else:
            self.velocity_x *= 0.8
            if abs(self.velocity_x) < 0.1:
                self.velocity_x = 0
                if self.on_ground and self.action not in ['jump', 'kick', 'dance']:
                    self.action = "idle"
        
        # 跳跃
        if keys[pygame.K_SPACE] and self.on_ground:
            self.velocity_y = -12
            self.on_ground = False
            self.action = "jump"
        
        # 鼠标交互
        if mouse_clicked:
            if mouse_pos[1] < SCREEN_HEIGHT // 3:  # 上区域 -> 挥手
                self.action = "wave"
                self.action_timer = 30
            elif mouse_pos[0] < SCREEN_WIDTH // 2:  # 左区域 -> 踢腿
                self.action = "kick"
                self.action_timer = 20
            else:  # 右区域 -> 跳舞
                self.action = "dance"
                self.action_timer = 60
        
        # 物理
        self.velocity_y += 0.6
        self.x += self.velocity_x
        self.y += self.velocity_y
        
        # 地面碰撞
        if self.y >= self.base_y:
            self.y = self.base_y
            self.velocity_y = 0
            self.on_ground = True
            if self.action == "jump":
                self.action = "idle"
        
        # 边界限制
        self.x = max(30, min(SCREEN_WIDTH - 30, self.x))
        
        # 动作计时器
        if self.action_timer > 0:
            self.action_timer -= 1
            if self.action_timer == 0 and self.action in ['wave', 'kick', 'dance']:
                self.action = "idle" if self.on_ground else "jump"
        
        # 无敌计时器
        if self.invincible:
            self.invincible_timer -= 1
            if self.invincible_timer <= 0:
                self.invincible = False
        
        # Combo 计时器
        if self.combo_timer > 0:
            self.combo_timer -= 1
            if self.combo_timer == 0:
                self.combo = 0
        
        # 走路动画帧
        self.walk_frame += 0.15
        
    def get_body_parts(self):
        """计算身体各部位坐标"""
        head_x = self.x
        head_y = self.y - self.body_length - self.head_radius
        
        neck_x = self.x
        neck_y = self.y - self.body_length
        
        body_bottom_x = self.x
        body_bottom_y = self.y
        
        direction = 1 if self.facing_right else -1
        
        # 根据动作调整手臂和腿部角度
        arm_angle = 0.3 * math.sin(self.walk_frame) if self.action == "walk" else 0
        leg_angle = 0.4 * math.sin(self.walk_frame) if self.action == "walk" else 0
        
        if self.action == "wave":
            arm_angle = 0.5 + 0.3 * math.sin(pygame.time.get_ticks() * 0.01)
        elif self.action == "kick":
            leg_angle = 1.0
        elif self.action == "dance":
            arm_angle = 0.8 * math.sin(pygame.time.get_ticks() * 0.008)
            leg_angle = 0.6 * math.sin(pygame.time.get_ticks() * 0.007)
        
        parts = {
            'head': (head_x, head_y),
            'neck': (neck_x, neck_y),
            'body_top': (neck_x, neck_y),
            'body_bottom': (body_bottom_x, body_bottom_y),
            'left_arm_start': (neck_x, neck_y + 5),
            'left_arm_end': (neck_x - self.arm_length * math.cos(math.pi/4 + arm_angle),
                           neck_y + 5 - self.arm_length * math.sin(math.pi/4 + arm_angle)),
            'right_arm_start': (neck_x, neck_y + 5),
            'right_arm_end': (neck_x + self.arm_length * math.cos(math.pi/4 - arm_angle),
                            neck_y + 5 - self.arm_length * math.sin(math.pi/4 - arm_angle)),
            'left_leg_start': (body_bottom_x, body_bottom_y),
            'left_leg_end': (body_bottom_x - self.leg_length * 0.5 * math.cos(math.pi/6 + leg_angle),
                           body_bottom_y + self.leg_length * math.sin(math.pi/6 + leg_angle)),
            'right_leg_start': (body_bottom_x, body_bottom_y),
            'right_leg_end': (body_bottom_x + self.leg_length * 0.5 * math.cos(math.pi/6 - leg_angle),
                            body_bottom_y + self.leg_length * math.sin(math.pi/6 - leg_angle)),
        }
        
        return parts
        
    def draw(self, surface):
        if self.invincible and (self.invincible_timer // 5) % 2 == 0:
            return  # 闪烁效果
            
        parts = self.get_body_parts()
        
        # 画头部
        pygame.draw.circle(surface, COLORS['SKIN'], 
                         (int(parts['head'][0]), int(parts['head'][1])), 
                         self.head_radius, 2)
        
        # 眼睛
        eye_offset = 5 if self.facing_right else -5
        eye_color = COLORS['BLACK']
        pygame.draw.circle(surface, eye_color, 
                         (int(parts['head'][0] + eye_offset), int(parts['head'][1] - 2)), 2)
        
        # 微笑
        smile_rect = pygame.Rect(parts['head'][0] - 5, parts['head'][1] + 2, 10, 6)
        pygame.draw.arc(surface, COLORS['BLACK'], smile_rect, 0, math.pi, 2)
        
        # 身体
        pygame.draw.line(surface, COLORS['BLACK'],
                        (int(parts['body_top'][0]), int(parts['body_top'][1])),
                        (int(parts['body_bottom'][0]), int(parts['body_bottom'][1])), 3)
        
        # 手臂
        for arm in ['left_arm', 'right_arm']:
            start = parts[f'{arm}_start']
            end = parts[f'{arm}_end']
            pygame.draw.line(surface, COLORS['BLACK'],
                           (int(start[0]), int(start[1])),
                           (int(end[0]), int(end[1])), 2)
        
        # 腿
        for leg in ['left_leg', 'right_leg']:
            start = parts[f'{leg}_start']
            end = parts[f'{leg}_end']
            pygame.draw.line(surface, COLORS['BLACK'],
                           (int(start[0]), int(start[1])),
                           (int(end[0]), int(end[1])), 3)
        
        # 鞋子
        shoe_size = 6
        for leg in ['left_leg', 'right_leg']:
            end = parts[f'{leg}_end']
            pygame.draw.circle(surface, COLORS['BROWN'],
                             (int(end[0]), int(end[1])), shoe_size)

    def get_rect(self):
        """获取碰撞矩形"""
        return pygame.Rect(self.x - 15, self.y - self.body_length - self.head_radius * 2, 30, 
                          self.body_length + self.head_radius * 2 + self.leg_length)

class Game:
    def __init__(self):
        self.state = GameState.MENU
        self.player = StickMan(SCREEN_WIDTH // 2, SCREEN_HEIGHT - 115)
        self.stars = [Star() for _ in range(60)]
        self.mountains = [Mountain(i) for i in range(3)]
        self.obstacles = []
        self.particles = []
        self.score = 0
        self.high_score = 0
        self.lives = 3
        self.scroll_speed = 4
        self.spawn_timer = 0
        self.font_large = pygame.font.Font(None, 72)
        self.font_medium = pygame.font.Font(None, 48)
        self.font_small = pygame.font.Font(None, 32)
        self.ground_y = SCREEN_HEIGHT - 105
        
        # 按钮
        self.play_button = pygame.Rect(SCREEN_WIDTH//2 - 100, SCREEN_HEIGHT//2, 200, 60)
        self.restart_button = pygame.Rect(SCREEN_WIDTH//2 - 100, SCREEN_HEIGHT//2 + 30, 200, 60)
        self.menu_button = pygame.Rect(SCREEN_WIDTH//2 - 100, SCREEN_HEIGHT//2 + 100, 200, 60)
        
    def spawn_obstacle(self):
        if len(self.obstacles) < 4:
            x = SCREEN_WIDTH + 50
            obs_type = random.choices(['spike', 'box', 'saw'], weights=[4, 3, 2])[0]
            self.obstacles.append(Obstacle(x, obs_type))
    
    def add_particles(self, x, y, color, count=15):
        for _ in range(count):
            self.particles.append(Particle(x, y, color))
    
    def handle_collisions(self):
        player_rect = self.player.get_rect()
        for obs in self.obstacles[:]:
            obs_rect = pygame.Rect(obs.x, obs.y, obs.width, obs.height)
            if player_rect.colliderect(obs_rect):
                if not self.player.invincible:
                    self.lives -= 1
                    self.player.invincible = True
                    self.player.invincible_timer = 90
                    self.add_particles(player_rect.centerx, player_rect.centery, COLORS['RED'], 20)
                    self.player.combo = 0
                    
                    if self.lives <= 0:
                        self.state = GameState.GAME_OVER
                        if self.score > self.high_score:
                            self.high_score = self.score
                
                self.obstacles.remove(obs)
            
            elif obs.x < -60:
                self.obstacles.remove(obs)
            
            elif not obs.passed and obs.x + obs.width < player_rect.left:
                obs.passed = True
                self.score += 10 + self.player.combo * 5
                self.player.combo += 1
                self.player.combo_timer = 120
                self.add_particles(obs.x + obs.width//2, obs.y + obs.height//2, COLORS['YELLOW'], 10)
    
    def update(self, keys, mouse_pos, mouse_clicked):
        if self.state == GameState.PLAYING:
            self.player.update(keys, mouse_pos, mouse_clicked)
            
            # 生成障碍物
            self.spawn_timer += 1
            if self.spawn_timer > random.randint(60, 150):
                self.spawn_obstacle()
                self.spawn_timer = 0
            
            # 更新障碍物
            for obs in self.obstacles:
                obs.update(self.scroll_speed)
            
            # 碰撞检测
            self.handle_collisions()
            
            # 更新粒子
            self.particles = [p for p in self.particles if p.update()]
            
            # 更新星星
            for star in self.stars:
                star.update()
                
    def draw_background(self):
        # 渐变天空
        for i in range(SCREEN_HEIGHT):
            ratio = i / SCREEN_HEIGHT
            color = (
                int(20 + 10 * ratio),
                int(10 + 20 * ratio),
                int(70 - 30 * ratio)
            )
            pygame.draw.line(screen, color, (0, i), (SCREEN_WIDTH, i))
        
        # 星星
        for star in self.stars:
            star.draw(screen)
        
        # 山脉
        for mountain in self.mountains:
            pygame.draw.polygon(screen, mountain.color, mountain.points)
        
        # 地面
        ground_rect = pygame.Rect(0, self.ground_y, SCREEN_WIDTH, 300)
        pygame.draw.rect(screen, COLORS['GROUND'], ground_rect)
        
        # 地面纹理线
        for i in range(0, SCREEN_WIDTH, 30):
            line_height = random.randint(2, 5)
            pygame.draw.line(screen, (45, 68, 92),
                           (i, self.ground_y),
                           (i, self.ground_y + line_height), 1)
    
    def draw_menu(self):
        self.draw_background()
        
        # 标题
        title = self.font_large.render("🎭 趣味火柴人", True, COLORS['YELLOW'])
        title_rect = title.get_rect(center=(SCREEN_WIDTH//2, 150))
        screen.blit(title, title_rect)
        
        # 副标题
        subtitle = self.font_small.render("冒险开始！", True, COLORS['CYAN'])
        subtitle_rect = subtitle.get_rect(center=(SCREEN_WIDTH//2, 210))
        screen.blit(subtitle, subtitle_rect)
        
        # 操作说明
        instructions = [
            "← → 移动 | 空格 跳跃",
            "🖱️ 上:挥手 | 左:踢腿 | 右:跳舞",
            "越过障碍得分！受伤会失去生命"
        ]
        for i, text in enumerate(instructions):
            inst = self.font_small.render(text, True, COLORS['WHITE'])
            inst_rect = inst.get_rect(center=(SCREEN_WIDTH//2, 280 + i * 40))
            screen.blit(inst, inst_rect)
        
        # 最高分
        if self.high_score > 0:
            score_text = self.font_medium.render(f"🏆 最高分: {self.high_score}", True, COLORS['YELLOW'])
            score_rect = score_text.get_rect(center=(SCREEN_WIDTH//2, 410))
            screen.blit(score_text, score_rect)
        
        # 开始按钮
        mouse_pos = pygame.mouse.get_pos()
        button_color = COLORS['GREEN'] if self.play_button.collidepoint(mouse_pos) else (60, 179, 113)
        pygame.draw.rect(screen, button_color, self.play_button, border_radius=10)
        pygame.draw.rect(screen, COLORS['YELLOW'], self.play_button, 3, border_radius=10)
        
        play_text = self.font_medium.render("开始游戏", True, COLORS['WHITE'])
        play_rect = play_text.get_rect(center=self.play_button.center)
        screen.blit(play_text, play_rect)
        
    def draw_game(self):
        self.draw_background()
        
        # 绘制障碍物
        for obs in self.obstacles:
            obs.draw(screen)
        
        # 绘制火柴人
        self.player.draw(screen)
        
        # 绘制粒子
        for particle in self.particles:
            particle.draw(screen)
        
        # HUD
        # 分数
        score_text = self.font_medium.render(f"分数: {self.score}", True, COLORS['YELLOW'])
        screen.blit(score_text, (20, 20))
        
        # 生命值
        hearts = "❤️" * self.lives + "🖤" * (3 - self.lives)
        lives_text = self.font_small.render(hearts, True, COLORS['RED'])
        screen.blit(lives_text, (20, 70))
        
        # Combo
        if self.player.combo > 1:
            combo_text = self.font_small.render(f"🔥 {self.player.combo}连击!", True, COLORS['ORANGE'])
            combo_rect = combo_text.get_rect(center=(SCREEN_WIDTH//2, 30))
            screen.blit(combo_text, combo_rect)
        
        # 操作提示
        hint = self.font_small.render("ESC: 暂停", True, COLORS['GRAY'])
        screen.blit(hint, (SCREEN_WIDTH - 120, 20))
    
    def draw_game_over(self):
        self.draw_background()
        
        # 暗色遮罩
        overlay = pygame.Surface((SCREEN_WIDTH, SCREEN_HEIGHT))
        overlay.set_alpha(128)
        overlay.fill((0, 0, 0))
        screen.blit(overlay, (0, 0))
        
        # 游戏结束文字
        game_over = self.font_large.render("💀 游戏结束", True, COLORS['RED'])
        game_over_rect = game_over.get_rect(center=(SCREEN_WIDTH//2, 150))
        screen.blit(game_over, game_over_rect)
        
        # 最终分数
        score_text = self.font_medium.render(f"得分: {self.score}", True, COLORS['YELLOW'])
        score_rect = score_text.get_rect(center=(SCREEN_WIDTH//2, 230))
        screen.blit(score_text, score_rect)
        
        if self.score == self.high_score and self.score > 0:
            new_record = self.font_small.render("🎉 新纪录！", True, COLORS['ORANGE'])
            new_record_rect = new_record.get_rect(center=(SCREEN_WIDTH//2, 270))
            screen.blit(new_record, new_record_rect)
        
        # 按钮
        mouse_pos = pygame.mouse.get_pos()
        
        # 重新开始
        restart_color = COLORS['GREEN'] if self.restart_button.collidepoint(mouse_pos) else (60, 179, 113)
        pygame.draw.rect(screen, restart_color, self.restart_button, border_radius=10)
        pygame.draw.rect(screen, COLORS['YELLOW'], self.restart_button, 3, border_radius=10)
        restart_text = self.font_medium.render("重新开始", True, COLORS['WHITE'])
        restart_rect = restart_text.get_rect(center=self.restart_button.center)
        screen.blit(restart_text, restart_rect)
        
        # 返回菜单
        menu_color = COLORS['BLUE'] if self.menu_button.collidepoint(mouse_pos) else (70, 130, 190)
        pygame.draw.rect(screen, menu_color, self.menu_button, border_radius=10)
        pygame.draw.rect(screen, COLORS['YELLOW'], self.menu_button, 3, border_radius=10)
        menu_text = self.font_medium.render("返回菜单", True, COLORS['WHITE'])
        menu_rect = menu_text.get_rect(center=self.menu_button.center)
        screen.blit(menu_text, menu_rect)
    
    def run(self):
        running = True
        mouse_clicked = False
        
        while running:
            mouse_clicked = False
            
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                
                if event.type == pygame.MOUSEBUTTONDOWN:
                    mouse_clicked = True
                    mouse_pos = pygame.mouse.get_pos()
                    
                    if self.state == GameState.MENU:
                        if self.play_button.collidepoint(mouse_pos):
                            self.state = GameState.PLAYING
                            self.__init__()
                            self.state = GameState.PLAYING
                    
                    elif self.state == GameState.GAME_OVER:
                        if self.restart_button.collidepoint(mouse_pos):
                            self.__init__()
                            self.state = GameState.PLAYING
                        elif self.menu_button.collidepoint(mouse_pos):
                            self.__init__()
                
                if event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        if self.state == GameState.PLAYING:
                            self.state = GameState.MENU
                        elif self.state == GameState.MENU:
                            pass
            
            keys = pygame.key.get_pressed()
            mouse_pos = pygame.mouse.get_pos()
            
            if self.state == GameState.PLAYING:
                self.update(keys, mouse_pos, mouse_clicked)
            
            # 绘制
            if self.state == GameState.MENU:
                self.draw_menu()
            elif self.state == GameState.PLAYING:
                self.draw_game()
            elif self.state == GameState.GAME_OVER:
                self.draw_game_over()
            
            pygame.display.flip()
            clock.tick(60)
        
        pygame.quit()

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