import tkinter as tk
from tkinter import ttk, messagebox, font
import random
import time
import json
import os
from datetime import datetime
from threading import Thread
import string

class TypingPracticeApp:
    def __init__(self, root):
        self.root = root
        self.root.title("打字练习软件")
        self.root.geometry("1000x700")
        self.root.configure(bg='#f5f5f5')
        
        # 练习文本库
        self.text_library = self.create_text_library()
        
        # 练习设置
        self.practice_mode = "句子练习"  # 默认模式
        self.difficulty = "中等"  # 默认难度
        
        # 计时相关
        self.start_time = None
        self.timer_running = False
        
        # 统计相关
        self.total_chars = 0
        self.correct_chars = 0
        self.wrong_chars = 0
        self.current_text = ""
        self.user_input = ""
        
        # 用户记录
        self.user_records = self.load_records()
        
        # 创建界面
        self.create_widgets()
        
        # 加载练习文本
        self.load_practice_text()
        
    def create_text_library(self):
        """创建练习文本库"""
        text_library = {
            "句子练习": {
                "简单": [
                    "Hello, how are you today?",
                    "I love programming in Python.",
                    "The quick brown fox jumps.",
                    "Learning to type is fun.",
                    "Good morning, have a nice day.",
                    "Python is a great language.",
                    "Practice makes perfect.",
                    "Typing speed matters.",
                    "Keep calm and code on.",
                    "Today is a beautiful day."
                ],
                "中等": [
                    "The quick brown fox jumps over the lazy dog, which is a classic pangram.",
                    "Programming is the process of creating a set of instructions that tell a computer how to perform a task.",
                    "Python is an interpreted, high-level, general-purpose programming language.",
                    "Practice typing regularly to improve your speed and accuracy over time.",
                    "The sun was shining brightly on the beautiful green fields of the countryside.",
                    "Artificial intelligence is transforming the way we live and work in modern society.",
                    "Consistent practice is the key to mastering any skill, including typing.",
                    "Technology continues to evolve at an unprecedented pace in the 21st century.",
                    "Effective communication skills are essential for success in any professional field.",
                    "Reading books regularly can significantly expand your knowledge and vocabulary."
                ],
                "困难": [
                    "The juxtaposition of quantum mechanics and general relativity presents one of the most profound challenges in contemporary theoretical physics, requiring innovative mathematical frameworks and conceptual paradigms.",
                    "Pneumonoultramicroscopicsilicovolcanoconiosis, a notoriously long word, exemplifies the complexity and richness of medical terminology derived from classical languages like Greek and Latin.",
                    "The epistemological implications of artificial neural networks challenge traditional philosophical conceptions of knowledge acquisition and cognitive processes in remarkable ways.",
                    "Sophisticated cryptographic algorithms employ intricate mathematical transformations to ensure robust data security in an increasingly interconnected digital ecosystem.",
                    "Metacognitive strategies involve conscious awareness and regulation of one's own cognitive processes during complex problem-solving activities."
                ]
            },
            "单词练习": {
                "简单": ["cat", "dog", "run", "jump", "play", "book", "pen", "desk", "chair", "table"],
                "中等": ["computer", "keyboard", "monitor", "software", "hardware", "network", "internet", "digital", "virtual", "algorithm"],
                "困难": ["phenomenon", "anthropology", "philosophical", "methodology", "psychological", "sophisticated", "infrastructure", "revolutionary", "technological", "multidimensional"]
            },
            "文章练习": {
                "简单": "Python is easy to learn. It has simple syntax. Many people like Python. It is good for beginners. You can do many things with Python.",
                "中等": """Python is a versatile programming language that's widely used in various domains including web development, 
data science, artificial intelligence, and automation. Its clear syntax and readability make it an excellent 
choice for beginners while its powerful libraries and frameworks support complex applications. The Python 
community is large and active, providing extensive documentation and support resources.""",
                "困难": """The evolution of programming paradigms has significantly influenced software development methodologies 
throughout computing history. From procedural programming to object-oriented design and functional 
programming, each paradigm introduces distinct conceptual frameworks for problem decomposition and 
solution architecture. Modern languages increasingly incorporate multiparadigm approaches, allowing 
developers to select the most appropriate abstraction level for specific problem domains. This 
flexibility facilitates the creation of robust, maintainable, and scalable software systems that 
can effectively address complex real-world challenges across diverse application domains."""
            }
        }
        return text_library
    
    def create_widgets(self):
        """创建界面组件"""
        # 设置字体
        self.title_font = ('Microsoft YaHei', 24, 'bold')
        self.subtitle_font = ('Microsoft YaHei', 12, 'bold')
        self.text_font = ('Consolas', 16)
        self.stats_font = ('Microsoft YaHei', 11)
        
        # 主框架
        main_frame = tk.Frame(self.root, bg='#f5f5f5')
        main_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 标题区域
        title_frame = tk.Frame(main_frame, bg='#2c3e50')
        title_frame.pack(fill='x', pady=(0, 20))
        
        tk.Label(title_frame, 
                text="⌨️ 打字练习软件",
                font=self.title_font,
                fg='white',
                bg='#2c3e50',
                pady=20).pack()
        
        # 控制面板
        control_frame = tk.Frame(main_frame, bg='#ecf0f1', relief='solid', bd=1)
        control_frame.pack(fill='x', pady=(0, 20))
        
        # 模式选择
        mode_frame = tk.Frame(control_frame, bg='#ecf0f1')
        mode_frame.pack(side='left', padx=20, pady=15)
        
        tk.Label(mode_frame, 
                text="练习模式:",
                font=self.subtitle_font,
                bg='#ecf0f1').pack(anchor='w')
        
        self.mode_var = tk.StringVar(value=self.practice_mode)
        mode_combo = ttk.Combobox(mode_frame,
                                 textvariable=self.mode_var,
                                 values=["句子练习", "单词练习", "文章练习"],
                                 state="readonly",
                                 width=15)
        mode_combo.pack(pady=(5, 0))
        mode_combo.bind('<<ComboboxSelected>>', self.on_mode_change)
        
        # 难度选择
        difficulty_frame = tk.Frame(control_frame, bg='#ecf0f1')
        difficulty_frame.pack(side='left', padx=20, pady=15)
        
        tk.Label(difficulty_frame,
                text="难度级别:",
                font=self.subtitle_font,
                bg='#ecf0f1').pack(anchor='w')
        
        self.difficulty_var = tk.StringVar(value=self.difficulty)
        difficulty_combo = ttk.Combobox(difficulty_frame,
                                       textvariable=self.difficulty_var,
                                       values=["简单", "中等", "困难"],
                                       state="readonly",
                                       width=15)
        difficulty_combo.pack(pady=(5, 0))
        difficulty_combo.bind('<<ComboboxSelected>>', self.on_difficulty_change)
        
        # 控制按钮
        button_frame = tk.Frame(control_frame, bg='#ecf0f1')
        button_frame.pack(side='right', padx=20, pady=15)
        
        self.start_button = tk.Button(button_frame,
                                     text="开始练习",
                                     command=self.start_practice,
                                     font=('Microsoft YaHei', 11, 'bold'),
                                     bg='#27ae60',
                                     fg='white',
                                     activebackground='#229954',
                                     relief='flat',
                                     padx=20,
                                     pady=8)
        self.start_button.pack(side='left', padx=5)
        
        self.reset_button = tk.Button(button_frame,
                                     text="重置",
                                     command=self.reset_practice,
                                     font=('Microsoft YaHei', 11),
                                     bg='#e67e22',
                                     fg='white',
                                     activebackground='#d35400',
                                     relief='flat',
                                     padx=20,
                                     pady=8)
        self.reset_button.pack(side='left', padx=5)
        
        self.new_text_button = tk.Button(button_frame,
                                        text="新文本",
                                        command=self.load_practice_text,
                                        font=('Microsoft YaHei', 11),
                                        bg='#3498db',
                                        fg='white',
                                        activebackground='#2980b9',
                                        relief='flat',
                                        padx=20,
                                        pady=8)
        self.new_text_button.pack(side='left', padx=5)
        
        # 主内容区域
        content_frame = tk.Frame(main_frame, bg='#f5f5f5')
        content_frame.pack(fill='both', expand=True)
        
        # 左侧 - 练习文本区域
        left_frame = tk.Frame(content_frame, bg='white', relief='solid', bd=1)
        left_frame.pack(side='left', fill='both', expand=True, padx=(0, 10))
        
        tk.Label(left_frame,
                text="📝 练习文本",
                font=self.subtitle_font,
                bg='#34495e',
                fg='white',
                padx=20,
                pady=10).pack(fill='x')
        
        # 练习文本显示
        text_frame = tk.Frame(left_frame, bg='white')
        text_frame.pack(fill='both', expand=True, padx=20, pady=20)
        
        self.practice_text = tk.Text(text_frame,
                                    font=self.text_font,
                                    bg='#f8f9fa',
                                    wrap='word',
                                    height=8,
                                    relief='flat',
                                    state='disabled')
        
        scrollbar = tk.Scrollbar(text_frame)
        self.practice_text.configure(yscrollcommand=scrollbar.set)
        scrollbar.configure(command=self.practice_text.yview)
        
        self.practice_text.pack(side='left', fill='both', expand=True)
        scrollbar.pack(side='right', fill='y')
        
        # 右侧 - 输入和统计区域
        right_frame = tk.Frame(content_frame, bg='white', relief='solid', bd=1)
        right_frame.pack(side='right', fill='both', expand=True)
        
        tk.Label(right_frame,
                text="⌨️ 输入区域",
                font=self.subtitle_font,
                bg='#34495e',
                fg='white',
                padx=20,
                pady=10).pack(fill='x')
        
        # 输入文本框
        self.input_text = tk.Text(right_frame,
                                 font=self.text_font,
                                 bg='white',
                                 wrap='word',
                                 height=8,
                                 relief='solid',
                                 bd=1)
        self.input_text.pack(fill='both', expand=True, padx=20, pady=20)
        self.input_text.bind('<Key>', self.on_key_press)
        self.input_text.config(state='disabled')
        
        # 统计信息区域
        stats_frame = tk.Frame(main_frame, bg='#ecf0f1', relief='solid', bd=1)
        stats_frame.pack(fill='x', pady=(20, 0))
        
        # 实时统计
        self.stats_vars = {
            'speed': tk.StringVar(value="0.0"),
            'accuracy': tk.StringVar(value="0.0%"),
            'time': tk.StringVar(value="0s"),
            'progress': tk.StringVar(value="0%")
        }
        
        stats_labels = [
            ("⏱️ 速度 (字/分)", self.stats_vars['speed']),
            ("🎯 准确率", self.stats_vars['accuracy']),
            ("⏰ 用时", self.stats_vars['time']),
            ("📈 进度", self.stats_vars['progress'])
        ]
        
        for i, (label, var) in enumerate(stats_labels):
            frame = tk.Frame(stats_frame, bg='#ecf0f1')
            frame.pack(side='left', expand=True, fill='both', padx=2, pady=10)
            
            tk.Label(frame,
                    text=label,
                    font=('Microsoft YaHei', 10),
                    bg='#ecf0f1').pack()
            
            tk.Label(frame,
                    textvariable=var,
                    font=('Microsoft YaHei', 16, 'bold'),
                    bg='#ecf0f1',
                    fg='#2c3e50').pack()
        
        # 历史记录区域
        records_frame = tk.Frame(main_frame, bg='white', relief='solid', bd=1)
        records_frame.pack(fill='x', pady=(20, 0))
        
        tk.Label(records_frame,
                text="📊 历史记录",
                font=self.subtitle_font,
                bg='#34495e',
                fg='white',
                padx=20,
                pady=10).pack(fill='x')
        
        # 记录显示区域
        self.records_text = tk.Text(records_frame,
                                   font=('Consolas', 10),
                                   bg='#f8f9fa',
                                   height=6,
                                   wrap='word',
                                   state='disabled')
        self.records_text.pack(fill='both', expand=True, padx=20, pady=20)
        
        # 底部状态栏
        self.status_var = tk.StringVar(value="准备就绪 - 选择模式并点击'开始练习'")
        status_bar = tk.Label(main_frame,
                             textvariable=self.status_var,
                             font=('Microsoft YaHei', 9),
                             bg='#2c3e50',
                             fg='white',
                             anchor='w',
                             padx=20)
        status_bar.pack(fill='x', pady=(20, 0))
        
        # 更新记录显示
        self.update_records_display()
        
    def load_practice_text(self):
        """加载练习文本"""
        mode = self.practice_mode
        difficulty = self.difficulty
        
        if mode == "文章练习":
            # 文章练习使用完整文章
            text = self.text_library[mode][difficulty]
        else:
            # 句子和单词练习从列表中随机选择
            text_list = self.text_library[mode][difficulty]
            if mode == "单词练习":
                # 对于单词练习，选择5-10个单词
                num_words = random.randint(5, 10)
                selected_words = random.sample(text_list, min(num_words, len(text_list)))
                text = " ".join(selected_words)
            else:
                # 句子练习
                text = random.choice(text_list)
        
        self.current_text = text
        self.display_practice_text()
        self.reset_practice()
    
    def display_practice_text(self):
        """显示练习文本"""
        self.practice_text.config(state='normal')
        self.practice_text.delete(1.0, tk.END)
        self.practice_text.insert(1.0, self.current_text)
        self.practice_text.config(state='disabled')
        
        # 重置输入区域
        self.input_text.config(state='normal')
        self.input_text.delete(1.0, tk.END)
        self.input_text.config(state='disabled')
        
        # 重置高亮
        self.highlight_text()
    
    def highlight_text(self):
        """高亮显示当前输入位置"""
        self.practice_text.tag_remove("current", "1.0", tk.END)
        self.practice_text.tag_remove("correct", "1.0", tk.END)
        self.practice_text.tag_remove("wrong", "1.0", tk.END)
        
        if self.user_input:
            # 标记正确和错误的字符
            for i, (input_char, target_char) in enumerate(zip(self.user_input, self.current_text)):
                if i >= len(self.current_text):
                    break
                    
                if input_char == target_char:
                    self.practice_text.tag_add("correct", f"1.{i}", f"1.{i+1}")
                else:
                    self.practice_text.tag_add("wrong", f"1.{i}", f"1.{i+1}")
            
            # 高亮当前输入位置
            if len(self.user_input) < len(self.current_text):
                self.practice_text.tag_add("current", f"1.{len(self.user_input)}", f"1.{len(self.user_input)+1}")
        
        # 设置标签样式
        self.practice_text.tag_config("current", background="#3498db", foreground="white")
        self.practice_text.tag_config("correct", background="#2ecc71", foreground="white")
        self.practice_text.tag_config("wrong", background="#e74c3c", foreground="white")
    
    def on_key_press(self, event):
        """处理键盘输入事件"""
        if not self.timer_running:
            return
            
        # 忽略控制键
        if len(event.char) == 0 or event.keysym in ('BackSpace', 'Delete', 'Return', 'Tab', 'Shift_L', 'Shift_R', 
                                                   'Control_L', 'Control_R', 'Alt_L', 'Alt_R'):
            if event.keysym == 'BackSpace':
                # 处理退格键
                if self.user_input:
                    self.user_input = self.user_input[:-1]
                    self.update_input_display()
            return
            
        # 添加字符
        self.user_input += event.char
        self.update_input_display()
        
        # 检查是否完成
        if len(self.user_input) >= len(self.current_text):
            self.finish_practice()
    
    def update_input_display(self):
        """更新输入显示和统计"""
        # 更新输入文本框
        self.input_text.delete(1.0, tk.END)
        self.input_text.insert(1.0, self.user_input)
        
        # 更新高亮
        self.highlight_text()
        
        # 更新统计
        self.update_stats()
    
    def update_stats(self):
        """更新统计信息"""
        if not self.start_time:
            return
            
        # 计算用时
        elapsed_time = time.time() - self.start_time
        
        # 计算正确字符数
        self.correct_chars = 0
        self.wrong_chars = 0
        
        for input_char, target_char in zip(self.user_input, self.current_text):
            if input_char == target_char:
                self.correct_chars += 1
            else:
                self.wrong_chars += 1
        
        # 计算额外错误的字符
        if len(self.user_input) > len(self.current_text):
            self.wrong_chars += len(self.user_input) - len(self.current_text)
        
        self.total_chars = len(self.user_input)
        
        # 计算速度 (字/分钟)
        if elapsed_time > 0:
            speed = (self.total_chars / 5) / (elapsed_time / 60)  # 假设5个字符=1个单词
        else:
            speed = 0
        
        # 计算准确率
        if self.total_chars > 0:
            accuracy = (self.correct_chars / self.total_chars) * 100
        else:
            accuracy = 0
        
        # 计算进度
        progress = (len(self.user_input) / len(self.current_text)) * 100
        
        # 更新显示
        self.stats_vars['speed'].set(f"{speed:.1f}")
        self.stats_vars['accuracy'].set(f"{accuracy:.1f}%")
        self.stats_vars['time'].set(f"{elapsed_time:.1f}s")
        self.stats_vars['progress'].set(f"{progress:.1f}%")
    
    def start_practice(self):
        """开始练习"""
        if self.timer_running:
            return
            
        self.timer_running = True
        self.start_time = time.time()
        self.user_input = ""
        
        # 启用输入
        self.input_text.config(state='normal')
        self.input_text.delete(1.0, tk.END)
        self.input_text.focus()
        
        # 更新按钮状态
        self.start_button.config(text="练习中...", state='disabled', bg='#95a5a6')
        
        # 更新状态
        self.status_var.set("练习进行中 - 开始输入！")
    
    def finish_practice(self):
        """完成练习"""
        if not self.timer_running:
            return
            
        self.timer_running = False
        elapsed_time = time.time() - self.start_time
        
        # 最终统计
        self.update_stats()
        
        # 保存记录
        self.save_record(elapsed_time)
        
        # 禁用输入
        self.input_text.config(state='disabled')
        
        # 更新按钮状态
        self.start_button.config(text="开始练习", state='normal', bg='#27ae60')
        
        # 显示结果
        speed = float(self.stats_vars['speed'].get())
        accuracy = float(self.stats_vars['accuracy'].get().replace('%', ''))
        
        result_message = f"练习完成！\n\n"
        result_message += f"速度: {speed:.1f} 字/分钟\n"
        result_message += f"准确率: {accuracy:.1f}%\n"
        result_message += f"用时: {elapsed_time:.1f} 秒\n"
        result_message += f"\n是否开始新的练习？"
        
        if messagebox.askyesno("练习完成", result_message):
            self.load_practice_text()
        else:
            self.status_var.set(f"练习完成 - 速度: {speed:.1f} 字/分钟, 准确率: {accuracy:.1f}%")
    
    def reset_practice(self):
        """重置练习"""
        self.timer_running = False
        self.start_time = None
        self.user_input = ""
        
        # 重置统计
        self.total_chars = 0
        self.correct_chars = 0
        self.wrong_chars = 0
        
        # 更新显示
        self.update_input_display()
        
        # 重置统计显示
        for var in self.stats_vars.values():
            var.set("0.0" if var != self.stats_vars['accuracy'] else "0.0%")
        
        # 启用开始按钮
        self.start_button.config(text="开始练习", state='normal', bg='#27ae60')
        
        # 禁用输入
        self.input_text.config(state='disabled')
        
        # 更新状态
        self.status_var.set("已重置 - 准备开始新练习")
    
    def on_mode_change(self, event):
        """处理模式更改"""
        self.practice_mode = self.mode_var.get()
        self.load_practice_text()
        self.status_var.set(f"已切换到 {self.practice_mode} 模式")
    
    def on_difficulty_change(self, event):
        """处理难度更改"""
        self.difficulty = self.difficulty_var.get()
        self.load_practice_text()
        self.status_var.set(f"已切换到 {self.difficulty} 难度")
    
    def load_records(self):
        """加载历史记录"""
        try:
            if os.path.exists("typing_records.json"):
                with open("typing_records.json", "r", encoding='utf-8') as f:
                    return json.load(f)
        except:
            pass
        return []
    
    def save_record(self, elapsed_time):
        """保存练习记录"""
        record = {
            "date": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "mode": self.practice_mode,
            "difficulty": self.difficulty,
            "speed": float(self.stats_vars['speed'].get()),
            "accuracy": float(self.stats_vars['accuracy'].get().replace('%', '')),
            "time": elapsed_time,
            "text_length": len(self.current_text)
        }
        
        self.user_records.append(record)
        
        # 只保留最近20条记录
        if len(self.user_records) > 20:
            self.user_records = self.user_records[-20:]
        
        # 保存到文件
        try:
            with open("typing_records.json", "w", encoding='utf-8') as f:
                json.dump(self.user_records, f, ensure_ascii=False, indent=2)
        except:
            pass
        
        # 更新显示
        self.update_records_display()
    
    def update_records_display(self):
        """更新历史记录显示"""
        self.records_text.config(state='normal')
        self.records_text.delete(1.0, tk.END)
        
        if not self.user_records:
            self.records_text.insert(1.0, "暂无历史记录")
        else:
            # 显示最近5条记录
            recent_records = self.user_records[-5:]
            recent_records.reverse()  # 最新的显示在最上面
            
            for i, record in enumerate(recent_records, 1):
                record_text = f"{i}. {record['date']} | "
                record_text += f"{record['mode']} ({record['difficulty']}) | "
                record_text += f"速度: {record['speed']:.1f} 字/分 | "
                record_text += f"准确率: {record['accuracy']:.1f}%\n"
                self.records_text.insert(tk.END, record_text)
        
        self.records_text.config(state='disabled')

def main():
    """主函数"""
    root = tk.Tk()
    app = TypingPracticeApp(root)
    root.mainloop()

if __name__ == "__main__":
    main()