import tkinter as tk
from tkinter import ttk, messagebox, font
import random
import json
import time
import threading
from collections import defaultdict
from datetime import datetime
import string

class AdvancedTypingTrainer:
    def __init__(self, root):
        self.root = root
        self.root.title("高级打字练习器 v2.0")
        self.root.geometry("1200x800")
        
        # 配置主题颜色
        self.colors = {
            'primary': '#2563eb',
            'secondary': '#64748b',
            'success': '#10b981',
            'danger': '#ef4444',
            'warning': '#f59e0b',
            'light': '#f8fafc',
            'dark': '#1e293b',
            'key_normal': '#334155',
            'key_active': '#3b82f6',
            'key_correct': '#10b981',
            'key_wrong': '#ef4444'
        }
        
        # 关卡系统
        self.levels = {
            1: {"name": "初级", "text_type": "英文单词", "length": 10, "speed_goal": 20, "accuracy_goal": 90},
            2: {"name": "中级", "text_type": "英文句子", "length": 20, "speed_goal": 40, "accuracy_goal": 95},
            3: {"name": "高级", "text_type": "英文文章", "length": 30, "speed_goal": 60, "accuracy_goal": 98},
            4: {"name": "专家", "text_type": "代码片段", "length": 40, "speed_goal": 80, "accuracy_goal": 99},
            5: {"name": "大师", "text_type": "混合内容", "length": 50, "speed_goal": 100, "accuracy_goal": 99}
        }
        
        self.current_level = 1
        self.current_text = ""
        self.current_char_index = 0
        self.start_time = None
        self.wpm = 0
        self.accuracy = 100
        self.total_typed = 0
        self.correct_typed = 0
        self.stats = defaultdict(list)
        
        # 键盘布局
        self.keyboard_rows = [
            ['`', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '-', '=', 'Backspace'],
            ['Tab', 'q', 'w', 'e', 'r', 't', 'y', 'u', 'i', 'o', 'p', '[', ']', '\\'],
            ['CapsLock', 'a', 's', 'd', 'f', 'g', 'h', 'j', 'k', 'l', ';', '\'', 'Enter'],
            ['Shift', 'z', 'x', 'c', 'v', 'b', 'n', 'm', ',', '.', '/', 'Shift'],
            ['Ctrl', 'Win', 'Alt', 'Space', 'Alt', 'Ctrl']
        ]
        
        self.finger_mapping = {
            'q': '左小指', 'a': '左小指', 'z': '左小指',
            'w': '左无名指', 's': '左无名指', 'x': '左无名指',
            'e': '左中指', 'd': '左中指', 'c': '左中指',
            'r': '左食指', 'f': '左食指', 'v': '左食指', 't': '左食指', 'g': '左食指', 'b': '左食指',
            'y': '右食指', 'u': '右食指', 'j': '右食指', 'm': '右食指', 'h': '右食指', 'n': '右食指',
            'i': '右中指', 'k': '右中指', ',': '右中指',
            'o': '右无名指', 'l': '右无名指', '.': '右无名指',
            'p': '右小指', ';': '右小指', '/': '右小指',
            '[': '右小指', ']': '右小指', '\\': '右小指',
            '\'': '右小指', 'Enter': '右小指', 'Backspace': '右小指',
            'Shift': '右小指/左小指', 'Tab': '左小指', 'CapsLock': '左小指',
            'Ctrl': '左小指/右小指', 'Alt': '左拇指/右拇指', 'Space': '左拇指/右拇指',
            'Win': '左拇指'
        }
        
        self.init_ui()
        self.load_texts()
        self.new_exercise()
        
    def init_ui(self):
        # 创建主容器
        main_container = ttk.Frame(self.root)
        main_container.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)
        
        # 左侧面板 - 打字区域
        left_frame = ttk.Frame(main_container)
        left_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))
        
        # 顶部控制面板
        control_frame = ttk.Frame(left_frame)
        control_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 关卡选择
        ttk.Label(control_frame, text="关卡:", font=('Arial', 11)).pack(side=tk.LEFT, padx=(0, 5))
        self.level_var = tk.StringVar()
        level_combo = ttk.Combobox(control_frame, textvariable=self.level_var, 
                                  values=[f"L{l}: {info['name']}" for l, info in self.levels.items()],
                                  state="readonly", width=15)
        level_combo.pack(side=tk.LEFT, padx=(0, 20))
        level_combo.set(f"L{self.current_level}: {self.levels[self.current_level]['name']}")
        level_combo.bind('<<ComboboxSelected>>', self.change_level)
        
        # 练习模式选择
        ttk.Label(control_frame, text="模式:", font=('Arial', 11)).pack(side=tk.LEFT, padx=(0, 5))
        self.mode_var = tk.StringVar(value="闯关模式")
        mode_combo = ttk.Combobox(control_frame, textvariable=self.mode_var, 
                                 values=["闯关模式", "自由练习", "指法专项"],
                                 state="readonly", width=12)
        mode_combo.pack(side=tk.LEFT, padx=(0, 20))
        
        # 控制按钮
        ttk.Button(control_frame, text="新练习", command=self.new_exercise).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="暂停/继续", command=self.toggle_pause).pack(side=tk.LEFT, padx=5)
        ttk.Button(control_frame, text="重置", command=self.reset_exercise).pack(side=tk.LEFT, padx=5)
        
        # 统计显示面板
        stats_frame = ttk.LabelFrame(left_frame, text="实时统计", padding=10)
        stats_frame.pack(fill=tk.X, pady=(0, 20))
        
        # 创建统计指标
        self.wpm_label = ttk.Label(stats_frame, text="速度: 0 WPM", font=('Arial', 12, 'bold'))
        self.wpm_label.pack(side=tk.LEFT, padx=20)
        
        self.accuracy_label = ttk.Label(stats_frame, text="准确率: 100%", font=('Arial', 12, 'bold'))
        self.accuracy_label.pack(side=tk.LEFT, padx=20)
        
        self.time_label = ttk.Label(stats_frame, text="时间: 0s", font=('Arial', 12, 'bold'))
        self.time_label.pack(side=tk.LEFT, padx=20)
        
        self.progress_label = ttk.Label(stats_frame, text="进度: 0%", font=('Arial', 12, 'bold'))
        self.progress_label.pack(side=tk.LEFT, padx=20)
        
        # 文本显示区域
        text_frame = ttk.LabelFrame(left_frame, text="练习文本", padding=15)
        text_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 20))
        
        self.text_display = tk.Text(text_frame, font=('Consolas', 18), wrap=tk.WORD,
                                   bg=self.colors['light'], relief=tk.FLAT, height=6)
        self.text_display.pack(fill=tk.BOTH, expand=True)
        
        # 输入区域
        input_frame = ttk.LabelFrame(left_frame, text="输入区域", padding=10)
        input_frame.pack(fill=tk.X)
        
        self.input_entry = tk.Entry(input_frame, font=('Consolas', 16), justify=tk.CENTER)
        self.input_entry.pack(fill=tk.X)
        self.input_entry.bind('<KeyRelease>', self.check_input)
        self.input_entry.focus_set()
        
        # 虚拟键盘框架
        keyboard_frame = ttk.LabelFrame(left_frame, text="虚拟键盘 (指法指引)", padding=10)
        keyboard_frame.pack(fill=tk.X)
        
        self.create_virtual_keyboard(keyboard_frame)
        
        # 右侧面板 - 统计和设置
        right_frame = ttk.Frame(main_container, width=300)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, padx=(10, 0))
        
        # 关卡信息
        level_info_frame = ttk.LabelFrame(right_frame, text="关卡信息", padding=15)
        level_info_frame.pack(fill=tk.X, pady=(0, 20))
        
        self.level_info_label = ttk.Label(level_info_frame, text="", font=('Arial', 10))
        self.level_info_label.pack(fill=tk.X)
        self.update_level_info()
        
        # 指法提示
        finger_info_frame = ttk.LabelFrame(right_frame, text="指法提示", padding=15)
        finger_info_frame.pack(fill=tk.X, pady=(0, 20))
        
        self.finger_label = ttk.Label(finger_info_frame, text="当前键位: 等待输入...", font=('Arial', 10))
        self.finger_label.pack(fill=tk.X)
        
        # 历史记录
        history_frame = ttk.LabelFrame(right_frame, text="历史记录", padding=15)
        history_frame.pack(fill=tk.BOTH, expand=True)
        
        # 创建滚动文本框显示历史
        self.history_text = tk.Text(history_frame, height=15, font=('Arial', 9), wrap=tk.WORD)
        scrollbar = ttk.Scrollbar(history_frame, command=self.history_text.yview)
        self.history_text.config(yscrollcommand=scrollbar.set)
        
        self.history_text.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
    def create_virtual_keyboard(self, parent):
        """创建虚拟键盘"""
        keyboard_container = ttk.Frame(parent)
        keyboard_container.pack(fill=tk.BOTH, expand=True)
        
        self.key_buttons = {}
        
        for row_idx, row in enumerate(self.keyboard_rows):
            row_frame = ttk.Frame(keyboard_container)
            row_frame.pack(fill=tk.X, pady=2)
            
            for key in row:
                btn = tk.Button(row_frame, text=key, font=('Arial', 9, 'bold'),
                               bg=self.colors['key_normal'], fg='white',
                               relief=tk.RAISED, bd=2, width=4 if key != 'Space' else 20,
                               height=2)
                
                if key == 'Space':
                    btn.config(width=20)
                elif key in ['Backspace', 'Enter', 'Tab', 'CapsLock', 'Shift', 'Ctrl', 'Alt', 'Win']:
                    btn.config(width=6)
                
                btn.pack(side=tk.LEFT, padx=1, pady=1)
                self.key_buttons[key] = btn
                
    def load_texts(self):
        """加载练习文本库"""
        self.text_library = {
            '英文单词': [
                "apple banana computer develop example fountain garden history",
                "journey keyboard language monitor network October program question",
                "reality science typical umbrella victory window xylophone yellow",
                "zebra action button camera digital elephant freedom graphics"
            ],
            '英文句子': [
                "The quick brown fox jumps over the lazy dog near the river bank.",
                "Programming is the process of creating a set of instructions that tell a computer how to perform a task.",
                "Practice makes perfect when it comes to improving your typing speed and accuracy on the keyboard.",
                "Every developer should learn touch typing to improve their coding efficiency and productivity."
            ],
            '英文文章': [
                "Artificial intelligence is transforming the world in unprecedented ways. From healthcare to transportation, "
                "AI applications are making processes more efficient and accessible. Machine learning algorithms can now "
                "diagnose diseases with greater accuracy than some human doctors, and self-driving cars are becoming a "
                "reality on our roads. The potential for AI to solve complex problems is enormous, but it also raises "
                "important ethical questions that society must address."
            ],
            '代码片段': [
                "def calculate_statistics(data):\n    mean = sum(data) / len(data)\n    variance = sum((x - mean) ** 2 for x in data) / len(data)\n    return {'mean': mean, 'variance': variance}",
                "class User:\n    def __init__(self, name, email):\n        self.name = name\n        self.email = email\n    \n    def display_info(self):\n        return f'User: {self.name} <{self.email}>'"
            ],
            '混合内容': [
                "Python 3.8 introduced the walrus operator (:=) which allows assignment expressions. For example: "
                "if (n := len(data)) > 10: print(f'List has {n} elements'). Meanwhile, JavaScript ES2020 added "
                "optional chaining with syntax: user?.address?.street. Type faster with accuracy!"
            ]
        }
        
    def new_exercise(self):
        """开始新的练习"""
        level_info = self.levels[self.current_level]
        text_type = level_info['text_type']
        length = level_info['length']
        
        # 选择练习文本
        if text_type in self.text_library:
            text = random.choice(self.text_library[text_type])
        else:
            text = random.choice(self.text_library['英文单词'])
        
        # 确保文本足够长
        while len(text) < length:
            text += " " + random.choice(self.text_library[text_type][0])
        
        self.current_text = text[:length * 5]  # 适当长度的文本
        self.current_char_index = 0
        self.total_typed = 0
        self.correct_typed = 0
        self.wpm = 0
        self.accuracy = 100
        self.start_time = time.time()
        
        # 更新显示
        self.update_text_display()
        self.input_entry.delete(0, tk.END)
        self.input_entry.config(state='normal')
        self.input_entry.focus_set()
        
        # 重置键盘高亮
        for btn in self.key_buttons.values():
            btn.config(bg=self.colors['key_normal'])
        
        # 开始计时
        self.update_stats()
        
    def update_text_display(self):
        """更新文本显示区域"""
        self.text_display.config(state='normal')
        self.text_display.delete(1.0, tk.END)
        
        # 用不同颜色显示文本
        for i, char in enumerate(self.current_text):
            if i < self.current_char_index:
                if char == ' ':
                    self.text_display.insert(tk.END, '✓', 'correct')
                else:
                    self.text_display.insert(tk.END, char, 'correct')
            elif i == self.current_char_index:
                self.text_display.insert(tk.END, char, 'current')
            else:
                self.text_display.insert(tk.END, char)
        
        # 配置标签样式
        self.text_display.tag_config('correct', background='#d1fae5', foreground='#065f46')
        self.text_display.tag_config('current', background='#3b82f6', foreground='white')
        self.text_display.tag_config('wrong', background='#fee2e2', foreground='#dc2626')
        
        self.text_display.config(state='disabled')
        
    def check_input(self, event):
        """检查输入"""
        if not self.current_text or self.current_char_index >= len(self.current_text):
            return
            
        input_text = self.input_entry.get()
        
        if not input_text:
            return
            
        current_char = self.current_text[self.current_char_index]
        last_char = input_text[-1]
        
        # 更新键盘高亮
        self.highlight_key(last_char)
        
        # 检查按键是否正确
        if last_char == current_char:
            self.correct_typed += 1
            self.current_char_index += 1
            
            # 检查是否完成
            if self.current_char_index >= len(self.current_text):
                self.exercise_complete()
        else:
            # 错误处理
            self.text_display.tag_add('wrong', f"1.{self.current_char_index}")
            self.text_display.tag_config('wrong', background='#fee2e2', foreground='#dc2626')
        
        self.total_typed += 1
        self.input_entry.delete(0, tk.END)
        self.update_text_display()
        
        # 显示指法提示
        finger = self.finger_mapping.get(last_char.upper() if last_char.isalpha() else last_char, "未知手指")
        self.finger_label.config(text=f"当前键位: {last_char} (使用{finger})")
        
    def highlight_key(self, key):
        """高亮虚拟键盘上的按键"""
        # 重置所有按键颜色
        for btn in self.key_buttons.values():
            btn.config(bg=self.colors['key_normal'])
        
        # 高亮当前按键
        key_upper = key.upper() if key.isalpha() else key
        if key_upper in self.key_buttons:
            self.key_buttons[key_upper].config(bg=self.colors['key_active'])
            
        # 特殊键处理
        if key == ' ':
            self.key_buttons['Space'].config(bg=self.colors['key_active'])
        
    def update_stats(self):
        """更新统计数据"""
        if self.start_time and self.total_typed > 0:
            elapsed_time = time.time() - self.start_time
            
            # 计算WPM（每分钟单词数）
            if elapsed_time > 0:
                self.wpm = int((self.correct_typed / 5) / (elapsed_time / 60))
                
            # 计算准确率
            if self.total_typed > 0:
                self.accuracy = int((self.correct_typed / self.total_typed) * 100)
            
            # 计算进度
            progress = int((self.current_char_index / len(self.current_text)) * 100)
            
            # 更新显示
            self.wpm_label.config(text=f"速度: {self.wpm} WPM")
            self.accuracy_label.config(text=f"准确率: {self.accuracy}%")
            self.time_label.config(text=f"时间: {int(elapsed_time)}s")
            self.progress_label.config(text=f"进度: {progress}%")
            
            # 检查关卡目标
            level_info = self.levels[self.current_level]
            if self.wpm >= level_info['speed_goal'] and self.accuracy >= level_info['accuracy_goal']:
                self.wpm_label.config(foreground=self.colors['success'])
            else:
                self.wpm_label.config(foreground='black')
                
            if self.accuracy >= level_info['accuracy_goal']:
                self.accuracy_label.config(foreground=self.colors['success'])
            else:
                self.accuracy_label.config(foreground='black')
        
        # 每秒更新一次
        if hasattr(self, 'running') and self.running:
            self.root.after(1000, self.update_stats)
            
    def exercise_complete(self):
        """练习完成"""
        elapsed_time = time.time() - self.start_time
        
        # 计算最终分数
        level_info = self.levels[self.current_level]
        speed_score = min(100, int((self.wpm / level_info['speed_goal']) * 100))
        accuracy_score = min(100, int((self.accuracy / 100) * 100))
        total_score = (speed_score + accuracy_score) // 2
        
        # 记录历史
        timestamp = datetime.now().strftime("%H:%M:%S")
        history_entry = f"[{timestamp}] 关卡{self.current_level} - "
        history_entry += f"速度: {self.wpm}WPM, 准确率: {self.accuracy}%, 时间: {int(elapsed_time)}s, 分数: {total_score}/100\n"
        
        self.history_text.insert(tk.END, history_entry)
        self.history_text.see(tk.END)
        
        # 检查是否可以进入下一关
        if self.wpm >= level_info['speed_goal'] and self.accuracy >= level_info['accuracy_goal']:
            if self.current_level < len(self.levels):
                response = messagebox.askyesno("恭喜！", 
                    f"恭喜完成第{self.current_level}关！\n"
                    f"速度: {self.wpm} WPM (目标: {level_info['speed_goal']})\n"
                    f"准确率: {self.accuracy}% (目标: {level_info['accuracy_goal']})\n\n"
                    "是否挑战下一关？")
                
                if response:
                    self.current_level += 1
                    self.level_var.set(f"L{self.current_level}: {self.levels[self.current_level]['name']}")
                    self.update_level_info()
                    self.new_exercise()
            else:
                messagebox.showinfo("通关！", "恭喜你完成了所有关卡！你是打字大师！")
        else:
            response = messagebox.askretrycancel("继续努力", 
                f"速度: {self.wpm} WPM (目标: {level_info['speed_goal']})\n"
                f"准确率: {self.accuracy}% (目标: {level_info['accuracy_goal']})\n\n"
                "目标尚未达成，是否重新挑战？")
            
            if response:
                self.new_exercise()
        
        self.input_entry.config(state='disabled')
        
    def change_level(self, event):
        """切换关卡"""
        level_str = self.level_var.get()
        new_level = int(level_str.split(':')[0][1:])
        
        if new_level != self.current_level:
            self.current_level = new_level
            self.update_level_info()
            self.new_exercise()
            
    def update_level_info(self):
        """更新关卡信息显示"""
        level_info = self.levels[self.current_level]
        info_text = (f"关卡: {level_info['name']}\n"
                    f"难度: {level_info['text_type']}\n"
                    f"文本长度: {level_info['length']}字符\n"
                    f"目标速度: {level_info['speed_goal']} WPM\n"
                    f"目标准确率: {level_info['accuracy_goal']}%")
        self.level_info_label.config(text=info_text)
        
    def toggle_pause(self):
        """暂停/继续练习"""
        if not hasattr(self, 'paused'):
            self.paused = False
            
        if not self.paused:
            self.paused = True
            self.input_entry.config(state='disabled')
        else:
            self.paused = False
            self.input_entry.config(state='normal')
            self.input_entry.focus_set()
            
    def reset_exercise(self):
        """重置当前练习"""
        self.new_exercise()

def main():
    root = tk.Tk()
    app = AdvancedTypingTrainer(root)
    app.running = True
    root.mainloop()
    app.running = False

if __name__ == "__main__":
    main()