import pygame
import random
import time
import sys
from typing import List, Tuple

# 初始化pygame
pygame.init()
pygame.font.init()

# 游戏常量
WIDTH, HEIGHT = 1000, 700
FPS = 60
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 150, 255)
YELLOW = (255, 255, 0)
PURPLE = (180, 0, 180)
GRAY = (200, 200, 200)
DARK_GRAY = (100, 100, 100)

# 创建游戏窗口
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Python打字练习")
clock = pygame.time.Clock()

# 字体
font_small = pygame.font.SysFont("consolas", 24)
font_medium = pygame.font.SysFont("consolas", 36)
font_large = pygame.font.SysFont("consolas", 48)
font_title = pygame.font.SysFont("consolas", 60, bold=True)

class FallingWord:
    def __init__(self, word: str, speed: float = 1.0):
        self.word = word
        self.display_word = word
        self.typed_part = ""
        self.remaining = word
        self.x = random.randint(50, WIDTH - 200)
        self.y = 0
        self.speed = speed
        self.color = WHITE
        self.correct = False
        self.wrong_attempts = 0
        self.max_wrong = 3
        
    def update(self, typed_char: str = None) -> Tuple[bool, bool]:
        """更新单词状态，返回(是否完成, 是否错误)"""
        self.y += self.speed
        
        if typed_char and self.remaining:
            if typed_char == self.remaining[0]:
                # 输入正确
                self.typed_part += typed_char
                self.remaining = self.remaining[1:]
                self.display_word = self.typed_part + self.remaining
                self.wrong_attempts = 0
                return len(self.remaining) == 0, False
            else:
                # 输入错误
                self.wrong_attempts += 1
                if self.wrong_attempts >= self.max_wrong:
                    self.color = RED
                else:
                    self.color = (255, 150, 150)  # 淡红色
                return False, True
        
        return False, False
    
    def draw(self, surface):
        # 绘制单词
        if self.correct:
            text_color = GREEN
        elif self.wrong_attempts > 0:
            text_color = self.color
        else:
            text_color = WHITE
        
        # 绘制已输入部分（绿色）和未输入部分（白色）
        if self.typed_part:
            typed_text = font_medium.render(self.typed_part, True, GREEN)
            remaining_text = font_medium.render(self.remaining, True, text_color)
            
            typed_rect = typed_text.get_rect()
            typed_rect.topleft = (self.x, self.y)
            
            remaining_rect = remaining_text.get_rect()
            remaining_rect.topleft = (self.x + typed_rect.width, self.y)
            
            surface.blit(typed_text, typed_rect)
            surface.blit(remaining_text, remaining_rect)
            
            # 绘制下划线
            pygame.draw.line(
                surface, 
                GREEN if not self.wrong_attempts else RED,
                (self.x, self.y + typed_rect.height + 5),
                (self.x + typed_rect.width, self.y + typed_rect.height + 5),
                2
            )
        else:
            text = font_medium.render(self.display_word, True, text_color)
            text_rect = text.get_rect()
            text_rect.topleft = (self.x, self.y)
            surface.blit(text, text_rect)
            
            # 绘制下划线
            if self.wrong_attempts > 0:
                pygame.draw.line(
                    surface, 
                    RED,
                    (self.x, self.y + text_rect.height + 5),
                    (self.x + text_rect.width, self.y + text_rect.height + 5),
                    2
                )

class TypingGame:
    def __init__(self):
        self.words = self.load_words()
        self.falling_words: List[FallingWord] = []
        self.score = 0
        self.lives = 3
        self.level = 1
        self.wpm = 0
        self.accuracy = 100.0
        self.total_chars = 0
        self.correct_chars = 0
        self.start_time = time.time()
        self.game_over = False
        self.paused = False
        self.game_mode = "normal"  # normal, speed, accuracy
        self.last_word_time = time.time()
        self.word_spawn_rate = 2.0  # 秒
        self.max_words = 8
        
        # 统计数据
        self.words_typed = 0
        self.words_missed = 0
        self.combo = 0
        self.max_combo = 0
        
    def load_words(self) -> List[str]:
        """加载单词库"""
        # 基础单词列表
        basic_words = [
            "python", "program", "computer", "keyboard", "algorithm",
            "function", "variable", "string", "integer", "boolean",
            "dictionary", "list", "tuple", "set", "module",
            "import", "class", "object", "method", "attribute",
            "exception", "debug", "compile", "execute", "runtime",
            "syntax", "semantic", "recursion", "iteration", "parameter"
        ]
        
        # 扩展单词列表（更复杂）
        advanced_words = [
            "algorithmic", "computational", "programming", "development",
            "environment", "framework", "library", "package", "repository",
            "inheritance", "polymorphism", "encapsulation", "abstraction",
            "interface", "implementation", "decomposition", "refactoring",
            "optimization", "parallelism", "asynchronous", "synchronous"
        ]
        
        # 根据难度混合单词
        all_words = basic_words + advanced_words
        return all_words
    
    def spawn_word(self):
        """生成新的下落单词"""
        if len(self.falling_words) >= self.max_words:
            return
        
        word = random.choice(self.words)
        speed = 1.0 + (self.level - 1) * 0.2
        self.falling_words.append(FallingWord(word, speed))
        self.last_word_time = time.time()
    
    def update(self, typed_char: str = None):
        """更新游戏状态"""
        if self.game_over or self.paused:
            return
        
        current_time = time.time()
        
        # 自动生成新单词
        if current_time - self.last_word_time > self.word_spawn_rate:
            self.spawn_word()
        
        # 更新所有下落单词
        completed_words = []
        wrong_input = False
        
        for word in self.falling_words[:]:
            # 检查单词是否掉落到底部
            if word.y > HEIGHT - 100:
                self.falling_words.remove(word)
                self.lives -= 1
                self.words_missed += 1
                self.combo = 0
                if self.lives <= 0:
                    self.game_over = True
                continue
            
            # 更新单词状态
            completed, wrong = word.update(typed_char)
            if completed:
                word.correct = True
                completed_words.append(word)
                self.score += 10 * len(word.word) + self.combo * 5
                self.words_typed += 1
                self.correct_chars += len(word.word)
                self.combo += 1
                self.max_combo = max(self.max_combo, self.combo)
            elif wrong:
                wrong_input = True
                self.combo = 0
        
        # 移除已完成的单词
        for word in completed_words:
            if word in self.falling_words:
                self.falling_words.remove(word)
        
        # 更新统计数据
        self.total_chars = self.correct_chars + sum(w.wrong_attempts for w in self.falling_words)
        if self.total_chars > 0:
            self.accuracy = (self.correct_chars / self.total_chars) * 100
        
        # 计算WPM
        elapsed_time = current_time - self.start_time
        if elapsed_time > 0:
            minutes = elapsed_time / 60
            self.wpm = int(self.correct_chars / 5 / minutes) if minutes > 0 else 0
        
        # 升级逻辑
        if self.score >= self.level * 100:
            self.level += 1
            self.word_spawn_rate = max(0.5, 2.0 - (self.level - 1) * 0.1)
            self.max_words = min(15, 8 + (self.level - 1))
    
    def handle_input(self, char: str):
        """处理用户输入"""
        if char and not self.game_over and not self.paused:
            self.update(char)
            return True
        return False
    
    def draw(self, surface):
        """绘制游戏界面"""
        # 绘制背景
        surface.fill((20, 20, 30))
        
        # 绘制网格背景
        for i in range(0, WIDTH, 50):
            pygame.draw.line(surface, (30, 30, 40), (i, 0), (i, HEIGHT), 1)
        for i in range(0, HEIGHT, 50):
            pygame.draw.line(surface, (30, 30, 40), (0, i), (WIDTH, i), 1)
        
        # 绘制标题
        title = font_title.render("打字练习", True, BLUE)
        surface.blit(title, (WIDTH//2 - title.get_width()//2, 20))
        
        # 绘制状态面板
        self.draw_stats_panel(surface)
        
        # 绘制键盘区域
        self.draw_keyboard(surface)
        
        # 绘制下落单词
        for word in self.falling_words:
            word.draw(surface)
        
        # 绘制生命值
        self.draw_lives(surface)
        
        # 绘制游戏状态
        if self.game_over:
            self.draw_game_over(surface)
        elif self.paused:
            self.draw_pause_screen(surface)
        
        # 绘制控制提示
        self.draw_controls(surface)
    
    def draw_stats_panel(self, surface):
        """绘制统计数据面板"""
        # 面板背景
        stats_rect = pygame.Rect(20, 100, 300, 200)
        pygame.draw.rect(surface, (40, 40, 60), stats_rect, border_radius=10)
        pygame.draw.rect(surface, BLUE, stats_rect, 2, border_radius=10)
        
        # 统计数据
        stats = [
            (f"得分: {self.score}", WHITE),
            (f"等级: {self.level}", WHITE),
            (f"WPM: {self.wpm}", GREEN if self.wpm > 50 else YELLOW if self.wpm > 30 else RED),
            (f"准确率: {self.accuracy:.1f}%", 
             GREEN if self.accuracy > 95 else YELLOW if self.accuracy > 85 else RED),
            (f"连击: {self.combo}", PURPLE if self.combo > 5 else WHITE),
            (f"最大连击: {self.max_combo}", PURPLE),
            (f"单词数: {self.words_typed}/{self.words_missed}", WHITE)
        ]
        
        y_offset = 120
        for text, color in stats:
            stat_text = font_small.render(text, True, color)
            surface.blit(stat_text, (40, y_offset))
            y_offset += 30
    
    def draw_keyboard(self, surface):
        """绘制键盘可视化"""
        # 键盘布局
        rows = [
            "1234567890-=",
            "qwertyuiop[]",
            "asdfghjkl;'",
            "zxcvbnm,./"
        ]
        
        key_width, key_height = 40, 40
        start_x = 350
        start_y = HEIGHT - 200
        
        for i, row in enumerate(rows):
            row_start_x = start_x + i * 20
            for j, key in enumerate(row):
                key_x = row_start_x + j * (key_width + 5)
                key_y = start_y + i * (key_height + 5)
                
                # 绘制按键
                key_rect = pygame.Rect(key_x, key_y, key_width, key_height)
                pygame.draw.rect(surface, (60, 60, 80), key_rect, border_radius=5)
                pygame.draw.rect(surface, (100, 100, 120), key_rect, 2, border_radius=5)
                
                # 绘制按键标签
                key_text = font_small.render(key.upper(), True, WHITE)
                text_rect = key_text.get_rect(center=(key_x + key_width//2, key_y + key_height//2))
                surface.blit(key_text, text_rect)
        
        # 空格键
        space_rect = pygame.Rect(start_x + 100, start_y + 4 * (key_height + 5), 300, key_height)
        pygame.draw.rect(surface, (60, 60, 80), space_rect, border_radius=5)
        pygame.draw.rect(surface, (100, 100, 120), space_rect, 2, border_radius=5)
        space_text = font_small.render("SPACE", True, WHITE)
        text_rect = space_text.get_rect(center=space_rect.center)
        surface.blit(space_text, text_rect)
    
    def draw_lives(self, surface):
        """绘制生命值"""
        life_text = font_medium.render("生命:", True, RED)
        surface.blit(life_text, (WIDTH - 200, 120))
        
        for i in range(3):
            color = RED if i < self.lives else DARK_GRAY
            x = WIDTH - 100 + i * 30
            pygame.draw.circle(surface, color, (x, 140), 10)
            pygame.draw.circle(surface, (255, 200, 200), (x, 140), 10, 2)
    
    def draw_game_over(self, surface):
        """绘制游戏结束画面"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 200))
        surface.blit(overlay, (0, 0))
        
        game_over = font_large.render("游戏结束!", True, RED)
        score_text = font_medium.render(f"最终得分: {self.score}", True, YELLOW)
        wpm_text = font_medium.render(f"最快速度: {self.wpm} WPM", True, YELLOW)
        accuracy_text = font_medium.render(f"准确率: {self.accuracy:.1f}%", True, YELLOW)
        restart_text = font_medium.render("按R键重新开始，按ESC退出", True, WHITE)
        
        surface.blit(game_over, (WIDTH//2 - game_over.get_width()//2, HEIGHT//2 - 100))
        surface.blit(score_text, (WIDTH//2 - score_text.get_width()//2, HEIGHT//2 - 30))
        surface.blit(wpm_text, (WIDTH//2 - wpm_text.get_width()//2, HEIGHT//2))
        surface.blit(accuracy_text, (WIDTH//2 - accuracy_text.get_width()//2, HEIGHT//2 + 30))
        surface.blit(restart_text, (WIDTH//2 - restart_text.get_width()//2, HEIGHT//2 + 80))
    
    def draw_pause_screen(self, surface):
        """绘制暂停画面"""
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 150))
        surface.blit(overlay, (0, 0))
        
        paused = font_large.render("游戏暂停", True, YELLOW)
        continue_text = font_medium.render("按P键继续游戏", True, WHITE)
        
        surface.blit(paused, (WIDTH//2 - paused.get_width()//2, HEIGHT//2 - 50))
        surface.blit(continue_text, (WIDTH//2 - continue_text.get_width()//2, HEIGHT//2 + 20))
    
    def draw_controls(self, surface):
        """绘制控制提示"""
        controls = [
            "控制说明:",
            "• 输入单词的字母来击落单词",
            "• 单词到达底部会扣除生命值",
            "• 正确输入单词得分，错误输入会标记错误",
            "• 按P键暂停/继续游戏",
            "• 按R键重新开始游戏",
            "• 按ESC键退出游戏"
        ]
        
        y_offset = HEIGHT - 100
        for i, text in enumerate(controls):
            color = BLUE if i == 0 else WHITE
            control_text = font_small.render(text, True, color)
            surface.blit(control_text, (20, y_offset))
            y_offset += 25
    
    def reset(self):
        """重置游戏"""
        self.__init__()

def main():
    game = TypingGame()
    running = True
    last_spawn_time = time.time()
    
    while running:
        # 处理事件
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                running = False
            
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    running = False
                
                elif event.key == pygame.K_r:
                    game.reset()
                
                elif event.key == pygame.K_p:
                    game.paused = not game.paused
                
                elif not game.game_over and not game.paused:
                    # 处理字母输入
                    if event.unicode.isalpha() or event.unicode in " -=';.,/[]":
                        game.handle_input(event.unicode.lower())
                    
                    # 处理退格键
                    elif event.key == pygame.K_BACKSPACE:
                        pass  # 可以添加退格功能
                    
                    # 处理空格键
                    elif event.key == pygame.K_SPACE:
                        game.handle_input(' ')
        
        # 更新游戏状态
        if not game.paused:
            current_time = time.time()
            
            # 定期生成新单词
            if current_time - last_spawn_time > game.word_spawn_rate and len(game.falling_words) < game.max_words:
                game.spawn_word()
                last_spawn_time = current_time
            
            # 更新游戏
            game.update()
        
        # 绘制游戏
        game.draw(screen)
        
        # 更新显示
        pygame.display.flip()
        clock.tick(FPS)
    
    pygame.quit()
    sys.exit()

if __name__ == "__main__":
    main()