import tkinter as tk
from tkinter import ttk, messagebox, font
import random
import time
import threading
from datetime import datetime
import json
import os


class TypingPracticeApp:
    def __init__(self, root):
        self.root = root
        self.root.title("打字练习软件 v1.0")
        self.root.geometry("1000x700")
        self.root.configure(bg="#f0f0f0")

        # 设置字体
        self.title_font = ("微软雅黑", 24, "bold")
        self.text_font = ("Consolas", 16)
        self.stats_font = ("微软雅黑", 12)

        # 练习文本库
        self.text_library = {
            "基础练习": [
                "The quick brown fox jumps over the lazy dog.",
                "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 makes perfect. Consistent effort leads to improvement over time.",
                "Typing speed is measured in words per minute, commonly abbreviated as WPM."
            ],
            "编程代码": [
                "def calculate_average(numbers):\n    total = sum(numbers)\n    count = len(numbers)\n    return total / count if count > 0 else 0",
                "for i in range(10):\n    if i % 2 == 0:\n        print(f'{i} is even')\n    else:\n        print(f'{i} is odd')",
                "class Car:\n    def __init__(self, make, model, year):\n        self.make = make\n        self.model = model\n        self.year = year",
                "import random\nnumbers = [random.randint(1, 100) for _ in range(20)]\nsorted_numbers = sorted(numbers)\nprint(f'Sorted: {sorted_numbers}')"
            ],
            "名言名句": [
                "The only way to do great work is to love what you do. - Steve Jobs",
                "Success is not final, failure is not fatal: it is the courage to continue that counts. - Winston Churchill",
                "The future belongs to those who believe in the beauty of their dreams. - Eleanor Roosevelt",
                "In the middle of difficulty lies opportunity. - Albert Einstein"
            ],
            "随机文章": [
                "The development of artificial intelligence has accelerated in recent years, with applications ranging from healthcare to autonomous vehicles. Researchers continue to explore both the potential benefits and ethical considerations of this rapidly advancing technology.",
                "Climate change represents one of the most significant challenges facing humanity today. Addressing this issue requires global cooperation, technological innovation, and changes in both individual behavior and industrial practices across multiple sectors of the economy.",
                "The Internet has transformed how people communicate, access information, and conduct business. This digital revolution has created new opportunities while also presenting challenges related to privacy, security, and the spread of misinformation in online spaces."
            ]
        }

        # 用户数据
        self.user_data = {
            "sessions": [],
            "best_scores": {
                "wpm": 0,
                "accuracy": 0
            }
        }

        # 练习状态变量
        self.current_text = ""
        self.user_input = ""
        self.start_time = None
        self.timer_running = False
        self.char_index = 0
        self.correct_chars = 0
        self.total_chars = 0
        self.current_mode = "基础练习"

        # 加载用户数据
        self.load_user_data()

        # 创建界面
        self.setup_ui()

    def setup_ui(self):
        # 主框架
        main_frame = tk.Frame(self.root, bg="#f0f0f0")
        main_frame.pack(fill=tk.BOTH, expand=True, padx=20, pady=20)

        # 标题
        title_label = tk.Label(
            main_frame,
            text="打字练习软件",
            font=self.title_font,
            bg="#f0f0f0",
            fg="#2c3e50"
        )
        title_label.pack(pady=(0, 20))

        # 控制面板框架
        control_frame = tk.Frame(main_frame, bg="#f0f0f0")
        control_frame.pack(fill=tk.X, pady=(0, 20))

        # 模式选择
        mode_label = tk.Label(
            control_frame,
            text="练习模式:",
            font=self.stats_font,
            bg="#f0f0f0"
        )
        mode_label.grid(row=0, column=0, padx=(0, 10))

        self.mode_var = tk.StringVar(value="基础练习")
        mode_menu = ttk.Combobox(
            control_frame,
            textvariable=self.mode_var,
            values=list(self.text_library.keys()),
            state="readonly",
            width=15
        )
        mode_menu.grid(row=0, column=1, padx=(0, 20))
        mode_menu.bind("<<ComboboxSelected>>", self.change_mode)

        # 难度选择
        difficulty_label = tk.Label(
            control_frame,
            text="难度:",
            font=self.stats_font,
            bg="#f0f0f0"
        )
        difficulty_label.grid(row=0, column=2, padx=(0, 10))

        self.difficulty_var = tk.StringVar(value="中等")
        difficulty_menu = ttk.Combobox(
            control_frame,
            textvariable=self.difficulty_var,
            values=["简单", "中等", "困难"],
            state="readonly",
            width=10
        )
        difficulty_menu.grid(row=0, column=3, padx=(0, 20))

        # 开始按钮
        start_button = tk.Button(
            control_frame,
            text="开始练习",
            command=self.start_practice,
            bg="#3498db",
            fg="white",
            font=self.stats_font,
            padx=20,
            pady=5
        )
        start_button.grid(row=0, column=4, padx=(0, 20))

        # 重置按钮
        reset_button = tk.Button(
            control_frame,
            text="重置",
            command=self.reset_practice,
            bg="#e74c3c",
            fg="white",
            font=self.stats_font,
            padx=20,
            pady=5
        )
        reset_button.grid(row=0, column=5)

        # 练习文本显示区域
        text_frame = tk.LabelFrame(
            main_frame, text="练习文本", font=self.stats_font, bg="#f0f0f0")
        text_frame.pack(fill=tk.BOTH, expand=True, pady=(0, 20))

        # 文本显示区域
        self.text_display = tk.Text(
            text_frame,
            font=self.text_font,
            wrap=tk.WORD,
            height=8,
            bg="#f8f9fa",
            relief=tk.FLAT,
            padx=20,
            pady=20
        )
        self.text_display.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        self.text_display.config(state=tk.DISABLED)

        # 输入区域框架
        input_frame = tk.LabelFrame(
            main_frame, text="输入区域", font=self.stats_font, bg="#f0f0f0")
        input_frame.pack(fill=tk.X, pady=(0, 20))

        # 输入文本框
        self.input_text = tk.Text(
            input_frame,
            font=self.text_font,
            wrap=tk.WORD,
            height=5,
            bg="#ffffff",
            relief=tk.SOLID,
            padx=20,
            pady=20
        )
        self.input_text.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        self.input_text.bind("<KeyRelease>", self.check_input)
        self.input_text.config(state=tk.DISABLED)

        # 统计信息框架
        stats_frame = tk.Frame(main_frame, bg="#f0f0f0")
        stats_frame.pack(fill=tk.X, pady=(0, 20))

        # 实时统计信息
        stats_labels = [
            ("时间:", "time_label", "0秒"),
            ("速度:", "wpm_label", "0 WPM"),
            ("准确率:", "accuracy_label", "0%"),
            ("进度:", "progress_label", "0%"),
            ("正确字符:", "correct_label", "0"),
            ("错误字符:", "errors_label", "0")
        ]

        for i, (text, var_name, default) in enumerate(stats_labels):
            label = tk.Label(stats_frame, text=text,
                             font=self.stats_font, bg="#f0f0f0")
            label.grid(row=0, column=i*2, padx=(0, 5), sticky=tk.W)

            setattr(self, var_name, tk.Label(
                stats_frame,
                text=default,
                font=self.stats_font,
                bg="#f0f0f0",
                fg="#2c3e50"
            ))
            getattr(self, var_name).grid(
                row=0, column=i*2+1, padx=(0, 20), sticky=tk.W)

        # 历史记录和最佳成绩框架
        history_frame = tk.Frame(main_frame, bg="#f0f0f0")
        history_frame.pack(fill=tk.BOTH, expand=True)

        # 最佳成绩
        best_frame = tk.LabelFrame(
            history_frame, text="最佳成绩", font=self.stats_font, bg="#f0f0f0")
        best_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=(0, 10))

        self.best_wpm_label = tk.Label(
            best_frame,
            text=f"最快速度: {self.user_data['best_scores']['wpm']} WPM",
            font=self.stats_font,
            bg="#f0f0f0"
        )
        self.best_wpm_label.pack(pady=10)

        self.best_accuracy_label = tk.Label(
            best_frame,
            text=f"最高准确率: {self.user_data['best_scores']['accuracy']}%",
            font=self.stats_font,
            bg="#f0f0f0"
        )
        self.best_accuracy_label.pack(pady=10)

        # 历史记录
        history_list_frame = tk.LabelFrame(
            history_frame, text="最近练习记录", font=self.stats_font, bg="#f0f0f0")
        history_list_frame.pack(
            side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=(10, 0))

        # 创建历史记录列表
        columns = ("日期", "模式", "速度", "准确率")
        self.history_tree = ttk.Treeview(
            history_list_frame,
            columns=columns,
            show="headings",
            height=8
        )

        for col in columns:
            self.history_tree.heading(col, text=col)
            self.history_tree.column(col, width=100)

        scrollbar = ttk.Scrollbar(
            history_list_frame, orient=tk.VERTICAL, command=self.history_tree.yview)
        self.history_tree.configure(yscrollcommand=scrollbar.set)

        self.history_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 填充历史记录
        self.update_history_display()

        # 状态栏
        status_frame = tk.Frame(main_frame, bg="#2c3e50", height=30)
        status_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=(10, 0))
        status_frame.pack_propagate(False)

        self.status_label = tk.Label(
            status_frame,
            text="就绪 - 请选择模式并点击'开始练习'",
            font=("微软雅黑", 10),
            bg="#2c3e50",
            fg="white"
        )
        self.status_label.pack(side=tk.LEFT, padx=10)

        # 初始化显示练习文本
        self.update_practice_text()

    def update_practice_text(self):
        """更新练习文本显示"""
        mode = self.mode_var.get()

        if mode in self.text_library:
            # 根据难度调整文本长度
            difficulty = self.difficulty_var.get()
            text_options = self.text_library[mode].copy()

            if difficulty == "简单":
                # 选择较短的文本
                self.current_text = min(text_options, key=len)
            elif difficulty == "困难":
                # 选择较长的文本
                self.current_text = max(text_options, key=len)
            else:  # 中等
                # 随机选择
                self.current_text = random.choice(text_options)
        else:
            self.current_text = random.choice(self.text_library["基础练习"])

        # 更新显示
        self.text_display.config(state=tk.NORMAL)
        self.text_display.delete(1.0, tk.END)
        self.text_display.insert(1.0, self.current_text)

        # 初始化高亮
        self.highlight_text()
        self.text_display.config(state=tk.DISABLED)

        # 重置输入框
        self.input_text.config(state=tk.NORMAL)
        self.input_text.delete(1.0, tk.END)
        self.input_text.config(state=tk.DISABLED)

        # 重置统计
        self.reset_stats()

    def highlight_text(self):
        """高亮显示文本中的字符状态"""
        self.text_display.tag_remove("correct", "1.0", tk.END)
        self.text_display.tag_remove("incorrect", "1.0", tk.END)
        self.text_display.tag_remove("current", "1.0", tk.END)

        # 标记已输入字符
        for i, char in enumerate(self.user_input):
            if i < len(self.current_text):
                if char == self.current_text[i]:
                    self.text_display.tag_add("correct", f"1.{i}", f"1.{i+1}")
                else:
                    self.text_display.tag_add(
                        "incorrect", f"1.{i}", f"1.{i+1}")

        # 标记当前位置
        if len(self.user_input) < len(self.current_text):
            self.text_display.tag_add(
                "current", f"1.{len(self.user_input)}", f"1.{len(self.user_input)+1}")

        # 配置标签样式
        self.text_display.tag_config(
            "correct", foreground="#27ae60", background="#d5f4e6")
        self.text_display.tag_config(
            "incorrect", foreground="#e74c3c", background="#fadbd8")
        self.text_display.tag_config(
            "current", background="#3498db", foreground="white")

    def start_practice(self):
        """开始练习"""
        if not self.timer_running:
            self.timer_running = True
            self.start_time = time.time()
            self.input_text.config(state=tk.NORMAL)
            self.input_text.focus()
            self.status_label.config(text="练习进行中...")

            # 启动计时器线程
            timer_thread = threading.Thread(
                target=self.update_timer, daemon=True)
            timer_thread.start()

    def reset_practice(self):
        """重置练习"""
        self.timer_running = False
        self.start_time = None
        self.user_input = ""
        self.char_index = 0
        self.correct_chars = 0
        self.total_chars = 0

        self.input_text.config(state=tk.NORMAL)
        self.input_text.delete(1.0, tk.END)
        self.input_text.config(state=tk.DISABLED)

        self.update_practice_text()
        self.reset_stats()
        self.status_label.config(text="已重置 - 请点击'开始练习'开始新的练习")

    def reset_stats(self):
        """重置统计信息"""
        self.time_label.config(text="0秒")
        self.wpm_label.config(text="0 WPM")
        self.accuracy_label.config(text="0%")
        self.progress_label.config(text="0%")
        self.correct_label.config(text="0")
        self.errors_label.config(text="0")

    def check_input(self, event):
        """检查用户输入"""
        if not self.timer_running:
            return

        # 获取用户输入
        self.user_input = self.input_text.get(1.0, tk.END).strip()

        # 更新高亮
        self.highlight_text()

        # 计算统计信息
        self.calculate_stats()

        # 检查是否完成
        if len(self.user_input) >= len(self.current_text):
            self.finish_practice()

    def calculate_stats(self):
        """计算统计信息"""
        # 计算正确字符数
        self.correct_chars = 0
        self.total_chars = len(self.user_input)

        for i, char in enumerate(self.user_input):
            if i < len(self.current_text) and char == self.current_text[i]:
                self.correct_chars += 1

        # 计算错误字符数
        errors = max(0, self.total_chars - self.correct_chars)

        # 计算准确率
        accuracy = (self.correct_chars / self.total_chars *
                    100) if self.total_chars > 0 else 0

        # 计算进度
        progress = (self.total_chars / len(self.current_text)
                    * 100) if len(self.current_text) > 0 else 0

        # 计算WPM（每分钟字数）
        elapsed_time = time.time() - self.start_time if self.start_time else 0
        minutes = elapsed_time / 60
        wpm = (self.correct_chars / 5) / minutes if minutes > 0 else 0

        # 更新显示
        self.time_label.config(text=f"{int(elapsed_time)}秒")
        self.wpm_label.config(text=f"{int(wpm)} WPM")
        self.accuracy_label.config(text=f"{accuracy:.1f}%")
        self.progress_label.config(text=f"{progress:.1f}%")
        self.correct_label.config(text=f"{self.correct_chars}")
        self.errors_label.config(text=f"{errors}")

    def update_timer(self):
        """更新计时器"""
        while self.timer_running:
            if self.start_time:
                elapsed_time = int(time.time() - self.start_time)
                self.time_label.config(text=f"{elapsed_time}秒")

                # 每0.1秒更新一次
                time.sleep(0.1)

    def finish_practice(self):
        """完成练习"""
        if not self.timer_running:
            return

        self.timer_running = False

        # 计算最终统计
        elapsed_time = time.time() - self.start_time
        minutes = elapsed_time / 60
        wpm = (self.correct_chars / 5) / minutes if minutes > 0 else 0
        accuracy = (self.correct_chars / self.total_chars *
                    100) if self.total_chars > 0 else 0

        # 保存练习记录
        session = {
            "date": datetime.now().strftime("%Y-%m-%d %H:%M"),
            "mode": self.current_mode,
            "wpm": int(wpm),
            "accuracy": round(accuracy, 1),
            "time": int(elapsed_time),
            "text_length": len(self.current_text)
        }

        self.user_data["sessions"].append(session)

        # 更新最佳成绩
        if wpm > self.user_data["best_scores"]["wpm"]:
            self.user_data["best_scores"]["wpm"] = int(wpm)
            self.best_wpm_label.config(text=f"最快速度: {int(wpm)} WPM")

        if accuracy > self.user_data["best_scores"]["accuracy"]:
            self.user_data["best_scores"]["accuracy"] = round(accuracy, 1)
            self.best_accuracy_label.config(text=f"最高准确率: {accuracy:.1f}%")

        # 保存数据
        self.save_user_data()

        # 更新历史记录显示
        self.update_history_display()

        # 显示结果
        result_text = f"练习完成!\n速度: {int(wpm)} WPM\n准确率: {accuracy:.1f}%\n时间: {int(elapsed_time)}秒"
        messagebox.showinfo("练习完成", result_text)

        self.status_label.config(text="练习完成! 点击'开始练习'重新开始或选择新模式")

    def change_mode(self, event=None):
        """更改练习模式"""
        self.current_mode = self.mode_var.get()
        self.reset_practice()
        self.status_label.config(text=f"已切换到{self.current_mode}模式，点击'开始练习'开始")

    def update_history_display(self):
        """更新历史记录显示"""
        # 清空现有记录
        for item in self.history_tree.get_children():
            self.history_tree.delete(item)

        # 添加最近10条记录
        recent_sessions = self.user_data["sessions"][-10:]
        for session in reversed(recent_sessions):
            self.history_tree.insert("", 0, values=(
                session["date"],
                session["mode"],
                f"{session['wpm']} WPM",
                f"{session['accuracy']}%"
            ))

    def save_user_data(self):
        """保存用户数据到文件"""
        try:
            with open("typing_practice_data.json", "w") as f:
                json.dump(self.user_data, f, indent=2)
        except Exception as e:
            print(f"保存数据时出错: {e}")

    def load_user_data(self):
        """从文件加载用户数据"""
        if os.path.exists("typing_practice_data.json"):
            try:
                with open("typing_practice_data.json", "r") as f:
                    self.user_data = json.load(f)
            except Exception as e:
                print(f"加载数据时出错: {e}")

    def on_closing(self):
        """关闭窗口时的处理"""
        self.save_user_data()
        self.root.destroy()


def main():
    root = tk.Tk()
    app = TypingPracticeApp(root)

    # 设置关闭窗口事件
    root.protocol("WM_DELETE_WINDOW", app.on_closing)

    # 设置窗口图标（如果有的话）
    try:
        root.iconbitmap("typing_icon.ico")
    except:
        pass

    root.mainloop()


if __name__ == "__main__":
    main()
