import tkinter as tk
from tkinter import font as tkfont
import time
import random
import math

PASSAGES = [
    {
        "title": "《春江花月夜》· 张若虚",
        "category": "唐诗",
        "text": "春江潮水连海平，海上明月共潮生。滟滟随波千万里，何处春江无月明。江流宛转绕芳甸，月照花林皆似霰。空里流霜不觉飞，汀上白沙看不见。江天一色无纤尘，皎皎空中孤月轮。"
    },
    {
        "title": "《将进酒》· 李白",
        "category": "唐诗",
        "text": "君不见黄河之水天上来，奔流到海不复回。君不见高堂明镜悲白发，朝如青丝暮成雪。人生得意须尽欢，莫使金樽空对月。天生我材必有用，千金散尽还复来。"
    },
    {
        "title": "《水调歌头》· 苏轼",
        "category": "宋词",
        "text": "明月几时有，把酒问青天。不知天上宫阙，今夕是何年。我欲乘风归去，又恐琼楼玉宇，高处不胜寒。起舞弄清影，何似在人间。转朱阁，低绮户，照无眠。不应有恨，何事长向别时圆。人有悲欢离合，月有阴晴圆缺，此事古难全。但愿人长久，千里共婵娟。"
    },
    {
        "title": "《岳阳楼记》· 范仲淹",
        "category": "古文",
        "text": "至若春和景明，波澜不惊，上下天光，一碧万顷，沙鸥翔集，锦鳞游泳，岸芷汀兰，郁郁青青。而或长烟一空，皓月千里，浮光跃金，静影沉璧，渔歌互答，此乐何极。"
    },
    {
        "title": "《滕王阁序》· 王勃",
        "category": "古文",
        "text": "落霞与孤鹜齐飞，秋水共长天一色。渔舟唱晚，响穷彭蠡之滨；雁阵惊寒，声断衡阳之浦。遥襟甫畅，逸兴遄飞。爽籁发而清风生，纤歌凝而白云遏。"
    },
    {
        "title": "《醉翁亭记》· 欧阳修",
        "category": "古文",
        "text": "环滁皆山也。其西南诸峰，林壑尤美，望之蔚然而深秀者，琅琊也。山行六七里，渐闻水声潺潺，而泻出于两峰之间者，酿泉也。峰回路转，有亭翼然临于泉上者，醉翁亭也。"
    },
    {
        "title": "《再别康桥》· 徐志摩",
        "category": "现代诗",
        "text": "轻轻的我走了，正如我轻轻的来；我轻轻的招手，作别西天的云彩。那河畔的金柳，是夕阳中的新娘；波光里的艳影，在我的心头荡漾。"
    },
    {
        "title": "《匆匆》· 朱自清",
        "category": "散文",
        "text": "燕子去了，有再来的时候；杨柳枯了，有再青的时候；桃花谢了，有再开的时候。但是，聪明的，你告诉我，我们的日子为什么一去不复返呢？是有人偷了他们罢，那是谁？又藏在何处呢？"
    },
    {
        "title": "《荷塘月色》· 朱自清",
        "category": "散文",
        "text": "曲曲折折的荷塘上面，弥望的是田田的叶子。叶子出水很高，像亭亭的舞女的裙。层层的叶子中间，零星地点缀着些白花，有袅娜地开着的，有羞涩地打着朵儿的。"
    },
    {
        "title": "《雨巷》· 戴望舒",
        "category": "现代诗",
        "text": "撑着油纸伞，独自彷徨在悠长、悠长又寂寥的雨巷，我希望逢着一个丁香一样地结着愁怨的姑娘。她是有丁香一样的颜色，丁香一样的芬芳，丁香一样的忧愁，在雨中哀怨，哀怨又彷徨。"
    },
    {
        "title": "《面朝大海，春暖花开》· 海子",
        "category": "现代诗",
        "text": "从明天起，做一个幸福的人，喂马、劈柴，周游世界。从明天起，关心粮食和蔬菜。我有一所房子，面朝大海，春暖花开。从明天起，和每一个亲人通信，告诉他们我的幸福。"
    },
    {
        "title": "《静夜思》· 李白",
        "category": "唐诗",
        "text": "床前明月光，疑是地上霜。举头望明月，低头思故乡。"
    },
    {
        "title": "《登鹳雀楼》· 王之涣",
        "category": "唐诗",
        "text": "白日依山尽，黄河入海流。欲穷千里目，更上一层楼。"
    },
    {
        "title": "《枫桥夜泊》· 张继",
        "category": "唐诗",
        "text": "月落乌啼霜满天，江枫渔火对愁眠。姑苏城外寒山寺，夜半钟声到客船。"
    },
    {
        "title": "《赤壁赋》· 苏轼",
        "category": "古文",
        "text": "壬戌之秋，七月既望，苏子与客泛舟游于赤壁之下。清风徐来，水波不兴。举酒属客，诵明月之诗，歌窈窕之章。少焉，月出于东山之上，徘徊于斗牛之间。白露横江，水光接天。"
    },
    {
        "title": "《兰亭集序》· 王羲之",
        "category": "古文",
        "text": "是日也，天朗气清，惠风和畅。仰观宇宙之大，俯察品类之盛，所以游目骋怀，足以极视听之娱，信可乐也。"
    },
    {
        "title": "《人间词话》· 王国维",
        "category": "文论",
        "text": "古今之成大事业、大学问者，必经过三种之境界。昨夜西风凋碧树，独上高楼，望尽天涯路，此第一境也。衣带渐宽终不悔，为伊消得人憔悴，此第二境也。众里寻他千百度，蓦然回首，那人却在灯火阑珊处，此第三境也。"
    },
    {
        "title": "《沁园春·雪》· 毛泽东",
        "category": "词",
        "text": "北国风光，千里冰封，万里雪飘。望长城内外，惟余莽莽；大河上下，顿失滔滔。山舞银蛇，原驰蜡象，欲与天公试比高。须晴日，看红装素裹，分外妖娆。"
    },
]


class Theme:
    BG_DARK = "#1a1a2e"
    BG_MID = "#16213e"
    BG_CARD = "#1f2b47"
    BG_INPUT = "#0f3460"
    ACCENT = "#e94560"
    ACCENT2 = "#53a8b6"
    GOLD = "#f0c38e"
    TEXT_PRIMARY = "#eaeaea"
    TEXT_SECONDARY = "#a0a8b8"
    TEXT_DIM = "#5a6478"
    CORRECT = "#4ecca3"
    WRONG = "#e94560"
    CURRENT_BG = "#f0c38e"
    CURRENT_FG = "#1a1a2e"
    PROGRESS_BG = "#2a3a5c"
    PROGRESS_FG = "#4ecca3"


class TypingApp:
    def __init__(self, root):
        self.root = root
        self.root.title("墨韵打字 —— 陶冶情操的打字练习")
        self.root.geometry("1100x750")
        self.root.minsize(900, 650)
        self.root.configure(bg=Theme.BG_DARK)

        self.current_passage = None
        self.typed_text = ""
        self.start_time = None
        self.is_typing = False
        self.is_finished = False
        self.total_keystrokes = 0
        self.correct_keystrokes = 0
        self.category_filter = "全部"

        self.font_title = tkfont.Font(family="Microsoft YaHei", size=22, weight="bold")
        self.font_subtitle = tkfont.Font(family="Microsoft YaHei", size=12)
        self.font_passage = tkfont.Font(family="Microsoft YaHei", size=20)
        self.font_input = tkfont.Font(family="Microsoft YaHei", size=18)
        self.font_stats_label = tkfont.Font(family="Microsoft YaHei", size=10)
        self.font_stats_value = tkfont.Font(family="Consolas", size=26, weight="bold")
        self.font_btn = tkfont.Font(family="Microsoft YaHei", size=11)
        self.font_category = tkfont.Font(family="Microsoft YaHei", size=10)
        self.font_result = tkfont.Font(family="Microsoft YaHei", size=16, weight="bold")
        self.font_quote = tkfont.Font(family="Microsoft YaHei", size=10, slant="italic")

        self._build_ui()
        self._load_random_passage()

    def _build_ui(self):
        top_frame = tk.Frame(self.root, bg=Theme.BG_MID, height=60)
        top_frame.pack(fill=tk.X, padx=0, pady=0)
        top_frame.pack_propagate(False)

        tk.Label(
            top_frame, text="✦ 墨 韵 打 字 ✦",
            font=self.font_title, fg=Theme.GOLD, bg=Theme.BG_MID
        ).pack(side=tk.LEFT, padx=30, pady=10)

        tk.Label(
            top_frame, text="在诗文中行走，于字句间修行",
            font=self.font_quote, fg=Theme.TEXT_SECONDARY, bg=Theme.BG_MID
        ).pack(side=tk.LEFT, padx=10, pady=10)

        cat_frame = tk.Frame(top_frame, bg=Theme.BG_MID)
        cat_frame.pack(side=tk.RIGHT, padx=20)

        categories = ["全部", "唐诗", "宋词", "词", "古文", "现代诗", "散文", "文论"]
        for cat in categories:
            btn = tk.Label(
                cat_frame, text=cat,
                font=self.font_category, fg=Theme.TEXT_SECONDARY, bg=Theme.BG_MID,
                padx=10, pady=4, cursor="hand2"
            )
            btn.pack(side=tk.LEFT, padx=2)
            btn.bind("<Button-1>", lambda e, c=cat: self._filter_category(c))
            btn.bind("<Enter>", lambda e, b=btn: b.configure(fg=Theme.GOLD))
            btn.bind("<Leave>", lambda e, b=btn, c=cat: b.configure(
                fg=Theme.GOLD if self.category_filter == c else Theme.TEXT_SECONDARY))

        content_frame = tk.Frame(self.root, bg=Theme.BG_DARK)
        content_frame.pack(fill=tk.BOTH, expand=True, padx=30, pady=15)

        self.title_label = tk.Label(
            content_frame, text="",
            font=self.font_subtitle, fg=Theme.ACCENT2, bg=Theme.BG_DARK, anchor="w"
        )
        self.title_label.pack(fill=tk.X, pady=(0, 8))

        passage_frame = tk.Frame(content_frame, bg=Theme.BG_CARD, bd=0)
        passage_frame.pack(fill=tk.X, pady=(0, 12))

        self.passage_canvas = tk.Canvas(
            passage_frame, bg=Theme.BG_CARD, highlightthickness=0, height=160
        )
        self.passage_canvas.pack(fill=tk.X, padx=20, pady=18)

        progress_frame = tk.Frame(content_frame, bg=Theme.BG_DARK)
        progress_frame.pack(fill=tk.X, pady=(0, 10))

        self.progress_canvas = tk.Canvas(
            progress_frame, bg=Theme.PROGRESS_BG, height=6, highlightthickness=0
        )
        self.progress_canvas.pack(fill=tk.X)

        input_frame = tk.Frame(content_frame, bg=Theme.BG_INPUT, bd=0)
        input_frame.pack(fill=tk.X, pady=(0, 15))

        self.input_text = tk.Text(
            input_frame, font=self.font_input, fg=Theme.TEXT_PRIMARY,
            bg=Theme.BG_INPUT, insertbackground=Theme.GOLD,
            relief=tk.FLAT, height=4, wrap=tk.WORD,
            padx=20, pady=15, bd=0, highlightthickness=0
        )
        self.input_text.pack(fill=tk.X)
        self.input_text.bind("<KeyRelease>", self._on_key_release)
        self.input_text.bind("<KeyPress>", self._on_key_press)
        self.input_text.bind("<Tab>", lambda e: "break")
        self.input_text.focus_set()

        stats_frame = tk.Frame(content_frame, bg=Theme.BG_DARK)
        stats_frame.pack(fill=tk.X, pady=(0, 5))

        self.stat_widgets = {}
        stat_items = [
            ("speed", "打字速度", "0", "字/分"),
            ("cpm", "字符速度", "0", "字符/分"),
            ("accuracy", "准确率", "0", "%"),
            ("time", "用时", "0:00", ""),
            ("progress", "进度", "0", "%"),
        ]

        for i, (key, label, value, unit) in enumerate(stat_items):
            card = tk.Frame(stats_frame, bg=Theme.BG_CARD, padx=18, pady=10)
            card.pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 8) if i < len(stat_items) - 1 else 0)

            tk.Label(card, text=label, font=self.font_stats_label,
                     fg=Theme.TEXT_SECONDARY, bg=Theme.BG_CARD).pack(anchor="w")
            val_frame = tk.Frame(card, bg=Theme.BG_CARD)
            val_frame.pack(anchor="w", pady=(2, 0))
            val_label = tk.Label(val_frame, text=value, font=self.font_stats_value,
                                 fg=Theme.GOLD, bg=Theme.BG_CARD)
            val_label.pack(side=tk.LEFT)
            if unit:
                tk.Label(val_frame, text=unit, font=self.font_stats_label,
                         fg=Theme.TEXT_DIM, bg=Theme.BG_CARD).pack(side=tk.LEFT, padx=(4, 0), anchor=tk.S)

            self.stat_widgets[key] = val_label

        bottom_frame = tk.Frame(self.root, bg=Theme.BG_MID, height=55)
        bottom_frame.pack(fill=tk.X, side=tk.BOTTOM)
        bottom_frame.pack_propagate(False)

        btn_frame = tk.Frame(bottom_frame, bg=Theme.BG_MID)
        btn_frame.pack(expand=True)

        self._make_button(btn_frame, "⟳  换一段", self._next_passage).pack(side=tk.LEFT, padx=8, pady=10)
        self._make_button(btn_frame, "↺  重新开始", self._reset).pack(side=tk.LEFT, padx=8, pady=10)
        self._make_button(btn_frame, "📝  再来一次", self._retry).pack(side=tk.LEFT, padx=8, pady=10)

    def _make_button(self, parent, text, command):
        btn = tk.Label(
            parent, text=text, font=self.font_btn,
            fg=Theme.TEXT_PRIMARY, bg=Theme.BG_INPUT,
            padx=18, pady=6, cursor="hand2"
        )
        btn.bind("<Button-1>", lambda e: command())
        btn.bind("<Enter>", lambda e: btn.configure(bg=Theme.ACCENT2, fg=Theme.BG_DARK))
        btn.bind("<Leave>", lambda e: btn.configure(bg=Theme.BG_INPUT, fg=Theme.TEXT_PRIMARY))
        return btn

    def _get_filtered_passages(self):
        if self.category_filter == "全部":
            return PASSAGES
        return [p for p in PASSAGES if p["category"] == self.category_filter]

    def _filter_category(self, category):
        self.category_filter = category
        self._load_random_passage()

    def _load_random_passage(self):
        filtered = self._get_filtered_passages()
        if not filtered:
            self.category_filter = "全部"
            filtered = PASSAGES
        self.current_passage = random.choice(filtered)
        self.title_label.config(text=f"📖 {self.current_passage['title']}  ·  {self.current_passage['category']}")
        self._reset()

    def _next_passage(self):
        self._load_random_passage()

    def _retry(self):
        if self.current_passage:
            self._reset()

    def _reset(self):
        self.typed_text = ""
        self.start_time = None
        self.is_typing = False
        self.is_finished = False
        self.total_keystrokes = 0
        self.correct_keystrokes = 0
        self.input_text.delete("1.0", tk.END)
        self.input_text.config(state=tk.NORMAL)
        self.input_text.focus_set()
        self._update_passage_display()
        self._update_stats()
        self._update_progress(0)

    def _update_passage_display(self):
        self.passage_canvas.delete("all")
        if not self.current_passage:
            return

        text = self.current_passage["text"]
        canvas_width = self.passage_canvas.winfo_width()
        if canvas_width < 50:
            canvas_width = 1000

        lines = self._wrap_text(text, canvas_width - 40, self.font_passage)

        x, y = 20, 15
        line_height = 38
        char_idx = 0
        typed_len = len(self.typed_text)

        for line in lines:
            cx = x
            for ch in line:
                if char_idx < typed_len:
                    if self.typed_text[char_idx] == ch:
                        color = Theme.CORRECT
                    else:
                        color = Theme.WRONG
                    self.passage_canvas.create_text(
                        cx, y, text=ch, font=self.font_passage,
                        fill=color, anchor="nw"
                    )
                elif char_idx == typed_len:
                    bbox = self.passage_canvas.create_text(
                        cx, y, text=ch, font=self.font_passage,
                        fill=Theme.CURRENT_FG, anchor="nw"
                    )
                    bb = self.passage_canvas.bbox(bbox)
                    if bb:
                        bg_rect = self.passage_canvas.create_rectangle(
                            bb[0] - 2, bb[1] - 2, bb[2] + 2, bb[3] + 2,
                            fill=Theme.CURRENT_BG, outline=""
                        )
                        self.passage_canvas.tag_lower(bg_rect, bbox)
                else:
                    self.passage_canvas.create_text(
                        cx, y, text=ch, font=self.font_passage,
                        fill=Theme.TEXT_DIM, anchor="nw"
                    )
                char_idx += 1
                cx += self.font_passage.measure(ch)
            y += line_height

        total_height = y + 10
        self.passage_canvas.config(height=max(total_height, 100))

    def _wrap_text(self, text, max_width, font):
        lines = []
        current_line = ""
        for ch in text:
            test_line = current_line + ch
            if font.measure(test_line) > max_width:
                if current_line:
                    lines.append(current_line)
                current_line = ch
            else:
                current_line = test_line
        if current_line:
            lines.append(current_line)
        return lines

    def _on_key_press(self, event):
        if self.is_finished:
            return

        if event.keysym in ("Shift_L", "Shift_R", "Control_L", "Control_R",
                            "Alt_L", "Alt_R", "Caps_Lock", "Escape", "F1", "F2",
                            "F3", "F4", "F5", "F6", "F7", "F8", "F9", "F10",
                            "F11", "F12", "Insert", "Home", "End", "Page_Up",
                            "Page_Down", "Up", "Down", "Left", "Right",
                            "Num_Lock", "Scroll_Lock", "Pause", "Print",
                            "Win_L", "Win_R", "Super_L", "Super_R"):
            return

        if not self.is_typing:
            self.is_typing = True
            self.start_time = time.time()

    def _on_key_release(self, event):
        if self.is_finished:
            return
        if event.keysym in ("Shift_L", "Shift_R", "Control_L", "Control_R",
                            "Alt_L", "Alt_R", "Caps_Lock", "Escape"):
            return

        current_input = self.input_text.get("1.0", tk.END).rstrip("\n")
        target = self.current_passage["text"]

        if len(current_input) > len(target):
            self.input_text.delete("1.0", tk.END)
            self.input_text.insert("1.0", current_input[:len(target)])
            current_input = current_input[:len(target)]

        self.typed_text = current_input

        self.total_keystrokes = len(self.typed_text)
        self.correct_keystrokes = sum(
            1 for i, ch in enumerate(self.typed_text) if i < len(target) and ch == target[i]
        )

        self._update_passage_display()
        self._update_stats()

        progress = len(self.typed_text) / len(target) if target else 0
        self._update_progress(progress)

        if len(self.typed_text) >= len(target):
            self._on_finish()

    def _update_stats(self):
        if not self.start_time:
            self.stat_widgets["speed"].config(text="0")
            self.stat_widgets["cpm"].config(text="0")
            self.stat_widgets["accuracy"].config(text="0")
            self.stat_widgets["time"].config(text="0:00")
            self.stat_widgets["progress"].config(text="0")
            return

        elapsed = time.time() - self.start_time
        if elapsed < 0.5:
            elapsed = 0.5

        target = self.current_passage["text"]
        typed_len = len(self.typed_text)

        cpm = int((typed_len / elapsed) * 60)

        wpm = cpm

        accuracy = int((self.correct_keystrokes / max(self.total_keystrokes, 1)) * 100)

        minutes = int(elapsed // 60)
        seconds = int(elapsed % 60)

        progress = int((typed_len / len(target)) * 100) if target else 0

        self.stat_widgets["speed"].config(text=str(wpm))
        self.stat_widgets["cpm"].config(text=str(cpm))
        self.stat_widgets["accuracy"].config(text=str(accuracy))
        self.stat_widgets["time"].config(text=f"{minutes}:{seconds:02d}")
        self.stat_widgets["progress"].config(text=str(progress))

        if accuracy >= 95:
            self.stat_widgets["accuracy"].config(fg=Theme.CORRECT)
        elif accuracy >= 80:
            self.stat_widgets["accuracy"].config(fg=Theme.GOLD)
        else:
            self.stat_widgets["accuracy"].config(fg=Theme.ACCENT)

    def _update_progress(self, ratio):
        self.progress_canvas.delete("all")
        w = self.progress_canvas.winfo_width()
        if w < 10:
            w = 1000
        h = 6
        self.progress_canvas.create_rectangle(0, 0, w, h, fill=Theme.PROGRESS_BG, outline="")
        bar_w = int(w * min(ratio, 1.0))
        if bar_w > 0:
            self.progress_canvas.create_rectangle(0, 0, bar_w, h, fill=Theme.PROGRESS_FG, outline="")

    def _on_finish(self):
        self.is_finished = True
        self.is_typing = False
        self.input_text.config(state=tk.DISABLED)

        elapsed = time.time() - self.start_time
        target = self.current_passage["text"]
        accuracy = int((self.correct_keystrokes / max(self.total_keystrokes, 1)) * 100)
        cpm = int((len(target) / elapsed) * 60)

        if accuracy >= 98 and cpm >= 60:
            comment = "🎉 出神入化，妙笔生花！"
            comment_color = Theme.CORRECT
        elif accuracy >= 95 and cpm >= 40:
            comment = "✨ 行云流水，游刃有余！"
            comment_color = Theme.CORRECT
        elif accuracy >= 90:
            comment = "📝 稳步前行，再接再厉！"
            comment_color = Theme.GOLD
        elif accuracy >= 80:
            comment = "💪 初窥门径，勤加练习！"
            comment_color = Theme.GOLD
        else:
            comment = "🌱 慢工出细活，不必急躁～"
            comment_color = Theme.ACCENT2

        self.passage_canvas.delete("all")
        cy = 30
        self.passage_canvas.create_text(
            20, cy, text="🎉 练习完成！", font=self.font_result,
            fill=Theme.GOLD, anchor="nw"
        )
        cy += 50
        minutes = int(elapsed // 60)
        seconds = int(elapsed % 60)
        result_text = f"速度 {cpm} 字/分  |  准确率 {accuracy}%  |  用时 {minutes}:{seconds:02d}"
        self.passage_canvas.create_text(
            20, cy, text=result_text, font=self.font_subtitle,
            fill=Theme.TEXT_PRIMARY, anchor="nw"
        )
        cy += 40
        self.passage_canvas.create_text(
            20, cy, text=comment, font=self.font_subtitle,
            fill=comment_color, anchor="nw"
        )
        self.passage_canvas.config(height=140)


def main():
    root = tk.Tk()

    try:
        root.iconbitmap(default="")
    except Exception:
        pass

    app = TypingApp(root)

    def on_resize(event):
        if not app.is_finished:
            app._update_passage_display()

    root.bind("<Configure>", on_resize)

    def tick():
        if app.is_typing and not app.is_finished:
            app._update_stats()
        root.after(500, tick)

    root.after(500, tick)
    root.mainloop()


if __name__ == "__main__":
    main()
