import tkinter as tk
from tkinter import ttk, messagebox
import json
import random
import time
import os

SAVE_FILE = "leaderboard.json"

TEXTS = {
    "en_word": [
        "function variable class object module import return",
        "keyboard monitor processor memory network server client"
    ],
    "en_sentence": [
        "Python is a powerful programming language.",
        "Typing practice improves coding speed significantly."
    ],
    "code": [
        "def hello():\n    print('Hello, world!')",
        "for i in range(10):\n    print(i)"
    ],
    "cn_word": [
        "人工智能 机器学习 深度学习 自然语言处理",
        "前端开发 后端开发 全栈工程师 DevOps"
    ],
    "cn_sentence": [
        "打字练习可以有效提高编程效率。",
        "坚持每天练习会有明显进步。"
    ]
}


class TypingApp:
    def __init__(self, root):
        self.root = root
        self.root.title("Typing Master Pro")
        self.root.geometry("820x540")
        self.dark = True

        self.text = ""
        self.start_time = None
        self.countdown = 0
        self.running = False

        self.leaderboard = self.load_leaderboard()
        self.create_widgets()
        self.apply_theme()

    # ---------- UI ----------
    def create_widgets(self):
        bar = tk.Frame(self.root)
        bar.pack(fill="x", pady=10)

        ttk.Label(bar, text="语言").pack(side="left", padx=5)
        self.lang = ttk.Combobox(
            bar, values=["en", "cn"], width=6, state="readonly"
        )
        self.lang.set("en")
        self.lang.pack(side="left")

        ttk.Label(bar, text="难度").pack(side="left", padx=5)
        self.mode = ttk.Combobox(
            bar, values=["word", "sentence", "code"],
            width=10, state="readonly"
        )
        self.mode.set("sentence")
        self.mode.pack(side="left")

        ttk.Label(bar, text="倒计时").pack(side="left", padx=5)
        self.time_box = ttk.Combobox(
            bar, values=[0, 30, 60], width=5, state="readonly"
        )
        self.time_box.set(30)
        self.time_box.pack(side="left")

        tk.Button(bar, text="开始", command=self.start).pack(
            side="left", padx=10
        )
        tk.Button(bar, text="🌙" if self.dark else "☀️",
                  command=self.toggle_theme).pack(side="right", padx=5)

        self.text_label = tk.Label(
            self.root, font=("Consolas", 15),
            wraplength=780, justify="left"
        )
        self.text_label.pack(pady=15)

        self.entry = tk.Text(self.root, height=5, font=("Consolas", 14))
        self.entry.pack(fill="x", padx=20)
        self.entry.bind("<KeyRelease>", self.check)

        self.stats = tk.Label(self.root, font=("Arial", 12))
        self.stats.pack(pady=8)

        self.rank = tk.Label(self.root, font=("Arial", 10))
        self.rank.pack()

    # ---------- Logic ----------
    def start(self):
        key = f"{self.lang.get()}_{self.mode.get()}"
        self.text = random.choice(TEXTS.get(key, TEXTS["en_sentence"]))
        self.text_label.config(text=self.text)
        self.entry.delete("1.0", tk.END)

        self.start_time = time.time()
        self.countdown = int(self.time_box.get())
        self.running = True
        self.update_timer()

    def check(self, _):
        typed = self.entry.get("1.0", tk.END).rstrip("\n")
        self.highlight(typed)

        if typed == self.text or (self.countdown <= 0 and self.running):
            self.finish(typed)

    def finish(self, typed):
        self.running = False
        elapsed = max(time.time() - self.start_time, 1)
        wpm = int(len(typed) / 5 / (elapsed / 60))
        acc = int(
            sum(
                1 for i, c in enumerate(typed)
                if i < len(self.text) and c == self.text[i]
            ) / max(len(typed), 1) * 100
        )

        self.save_score(wpm, acc)
        messagebox.showinfo("完成", f"WPM: {wpm}\n准确率: {acc}%")

    # ---------- Highlight ----------
    def highlight(self, typed):
        self.text_label.config(text="")
        for i, ch in enumerate(self.text):
            color = "#ffffff"
            if i < len(typed):
                color = "#4caf50" if typed[i] == ch else "#f44336"
            self.text_label.config(
                text=self.text_label.cget("text") + ch,
                fg=color
            )

    # ---------- Timer ----------
    def update_timer(self):
        if not self.running:
            return
        if self.countdown > 0:
            self.countdown -= 1
            self.stats.config(text=f"剩余时间：{self.countdown}s")
            self.root.after(1000, self.update_timer)
        else:
            self.finish(self.entry.get("1.0", tk.END))

    # ---------- Leaderboard ----------
    def load_leaderboard(self):
        if os.path.exists(SAVE_FILE):
            with open(SAVE_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        return []

    def save_score(self, wpm, acc):
        self.leaderboard.append({"wpm": wpm, "acc": acc})
        self.leaderboard.sort(key=lambda x: x["wpm"], reverse=True)
        self.leaderboard = self.leaderboard[:5]
        with open(SAVE_FILE, "w", encoding="utf-8") as f:
            json.dump(self.leaderboard, f, ensure_ascii=False)

    # ---------- Theme ----------
    def apply_theme(self):
        bg, fg = ("#1e1e1e", "#ffffff") if self.dark else ("#f5f5f5", "#000000")
        self.root.configure(bg=bg)
        for w in self.root.winfo_children():
            try:
                w.configure(bg=bg, fg=fg)
            except:
                pass

    def toggle_theme(self):
        self.dark = not self.dark
        self.apply_theme()


if __name__ == "__main__":
    root = tk.Tk()
    TypingApp(root)
    root.mainloop()