import tkinter as tk
from tkinter import ttk, messagebox
import random
import sys

# 尝试导入 matplotlib + Pillow 用于渲染 LaTeX 到图片（可选）
USE_MATPLOTLIB = False
try:
    import matplotlib
    matplotlib.use("Agg")
    import matplotlib.pyplot as plt
    from PIL import Image, ImageTk
    USE_MATPLOTLIB = True
except Exception:
    USE_MATPLOTLIB = False

# 示例公式库：每项包含 id/title/latex/description/example
formulas = [
    {
        "id": "pythagoras",
        "title": "勾股定理 (Pythagorean theorem)",
        "latex": r"c^2 = a^2 + b^2",
        "description": "直角三角形斜边的平方等于两直角边的平方和。",
        "example": "如果 a=3, b=4，则 c=5。"
    },
    {
        "id": "quadratic",
        "title": "二次方程求根公式 (Quadratic formula)",
        "latex": r"x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}",
        "description": "求解 ax^2 + bx + c = 0 的根（a ≠ 0）。",
        "example": "例如 x^2 - 3x + 2 = 0 的根为 x=1,2。"
    },
    {
        "id": "euler",
        "title": "欧拉公式 (Euler's identity)",
        "latex": r"e^{i\pi} + 1 = 0",
        "description": "复分析中的优美恒等式，将 e,i,π,1,0 联系在一起。",
        "example": ""
    },
    {
        "id": "derivative_product",
        "title": "乘积法则 (Product rule)",
        "latex": r"\frac{d}{dx}[u(x)v(x)] = u'(x)v(x) + u(x)v'(x)",
        "description": "求导的乘积法则。",
        "example": ""
    },
    {
        "id": "integral_def",
        "title": "定积分定义（黎曼）",
        "latex": r"\int_a^b f(x)\,dx = \lim_{n\to\infty} \sum_{i=1}^n f(x_i^*)\Delta x_i",
        "description": "定积分的黎曼和定义（简略）。",
        "example": ""
    }
]

class FormulaApp(tk.Tk):
    def __init__(self, formulas):
        super().__init__()
        self.title("数学公式查询")
        self.geometry("900x600")
        self.formulas = formulas
        self.filtered = list(range(len(formulas)))
        self.current_idx = 0

        self.create_widgets()
        self.populate_list()
        if self.filtered:
            self.select_by_filtered_pos(0)

    def create_widgets(self):
        top = ttk.Frame(self)
        top.pack(side="top", fill="x", padx=8, pady=6)

        ttk.Label(top, text="搜索：").pack(side="left")
        self.search_var = tk.StringVar()
        search_entry = ttk.Entry(top, textvariable=self.search_var, width=40)
        search_entry.pack(side="left", padx=(4,6))
        search_entry.bind("<Return>", lambda e: self.do_search())

        ttk.Button(top, text="搜索", command=self.do_search).pack(side="left")
        ttk.Button(top, text="显示全部", command=self.show_all).pack(side="left", padx=6)
        ttk.Button(top, text="随机一条", command=self.random_formula).pack(side="left")

        main = ttk.PanedWindow(self, orient="horizontal")
        main.pack(fill="both", expand=True, padx=8, pady=6)

        left = ttk.Frame(main, width=280)
        main.add(left, weight=1)

        right = ttk.Frame(main)
        main.add(right, weight=3)

        self.listbox = tk.Listbox(left, exportselection=False)
        self.listbox.pack(side="left", fill="both", expand=True)
        self.listbox.bind("<<ListboxSelect>>", self.on_list_select)

        sb = ttk.Scrollbar(left, orient="vertical", command=self.listbox.yview)
        sb.pack(side="right", fill="y")
        self.listbox.config(yscrollcommand=sb.set)

        # 右侧顶部：标题与按钮
        title_frame = ttk.Frame(right)
        title_frame.pack(fill="x")

        self.title_label = ttk.Label(title_frame, text="", font=("Helvetica", 16, "bold"))
        self.title_label.pack(anchor="w")

        btn_frame = ttk.Frame(title_frame)
        btn_frame.pack(anchor="e")

        ttk.Button(btn_frame, text="复制 LaTeX", command=self.copy_latex).pack(side="left", padx=4)
        ttk.Button(btn_frame, text="渲染 (matplotlib)", command=self.render_latex).pack(side="left", padx=4)

        # 公式渲染区（图片）和 LaTeX 源
        display_frame = ttk.Frame(right)
        display_frame.pack(fill="both", expand=True)

        # image label for rendered formula
        self.image_label = ttk.Label(display_frame)
        self.image_label.pack(fill="both", expand=False, pady=(6,4))

        # LaTeX source text (readonly)
        ttk.Label(display_frame, text="LaTeX 源：").pack(anchor="w")
        self.latex_text = tk.Text(display_frame, height=3, wrap="none")
        self.latex_text.pack(fill="x", padx=2, pady=(0,6))
        self.latex_text.config(state="disabled")

        # description and example
        ttk.Label(display_frame, text="说明：").pack(anchor="w")
        self.desc_var = tk.StringVar()
        ttk.Label(display_frame, textvariable=self.desc_var, wraplength=500, foreground="black").pack(anchor="w", pady=(0,6))

        ttk.Label(display_frame, text="示例/备注：").pack(anchor="w")
        self.example_var = tk.StringVar()
        ttk.Label(display_frame, textvariable=self.example_var, wraplength=500, foreground="gray").pack(anchor="w")

        bottom = ttk.Frame(right)
        bottom.pack(fill="x", pady=6)
        ttk.Button(bottom, text="上一条", command=self.prev).pack(side="left", padx=6)
        ttk.Button(bottom, text="下一条", command=self.next).pack(side="left", padx=6)

    def populate_list(self):
        self.listbox.delete(0, "end")
        for i in self.filtered:
            item = self.formulas[i]
            self.listbox.insert("end", f"{item['title']}")

    def select_by_filtered_pos(self, pos):
        if not self.filtered:
            return
        pos = max(0, min(pos, len(self.filtered)-1))
        self.current_idx = self.filtered[pos]
        self.listbox.select_clear(0, "end")
        self.listbox.select_set(pos)
        self.listbox.activate(pos)
        self.listbox.see(pos)
        self.show_formula(self.current_idx)

    def on_list_select(self, evt):
        sel = self.listbox.curselection()
        if not sel:
            return
        pos = sel[0]
        self.current_idx = self.filtered[pos]
        self.show_formula(self.current_idx)

    def show_formula(self, idx):
        f = self.formulas[idx]
        self.title_label.config(text=f.get("title",""))
        # LaTeX 源
        self.latex_text.config(state="normal")
        self.latex_text.delete("1.0", "end")
        self.latex_text.insert("end", f.get("latex",""))
        self.latex_text.config(state="disabled")
        # description/example
        self.desc_var.set(f.get("description",""))
        self.example_var.set(f.get("example",""))
        # clear rendered image
        self.image_label.config(image="", text="")
        self._photo = None

    def do_search(self):
        kw = self.search_var.get().strip().lower()
        if not kw:
            self.show_all()
            return
        self.filtered = []
        for i, f in enumerate(self.formulas):
            hay = " ".join([f.get("title",""), f.get("latex",""), f.get("description",""), f.get("example","")])
            if kw in hay.lower():
                self.filtered.append(i)
        if not self.filtered:
            messagebox.showinfo("搜索", f"未找到包含“{kw}”的公式。")
            return
        self.populate_list()
        self.select_by_filtered_pos(0)

    def show_all(self):
        self.filtered = list(range(len(self.formulas)))
        self.populate_list()
        if self.filtered:
            self.select_by_filtered_pos(0)

    def random_formula(self):
        if not self.formulas:
            return
        idx = random.randrange(len(self.formulas))
        # 若在 filtered 中则在当前列表中选择，否则切换为全量
        if idx in self.filtered:
            pos = self.filtered.index(idx)
            self.select_by_filtered_pos(pos)
        else:
            self.filtered = list(range(len(self.formulas)))
            self.populate_list()
            pos = self.filtered.index(idx)
            self.select_by_filtered_pos(pos)

    def prev(self):
        if not self.filtered:
            return
        try:
            pos = self.filtered.index(self.current_idx)
        except ValueError:
            pos = 0
        pos = (pos - 1) % len(self.filtered)
        self.select_by_filtered_pos(pos)

    def next(self):
        if not self.filtered:
            return
        try:
            pos = self.filtered.index(self.current_idx)
        except ValueError:
            pos = 0
        pos = (pos + 1) % len(self.filtered)
        self.select_by_filtered_pos(pos)

    def copy_latex(self):
        f = self.formulas[self.current_idx]
        latex = f.get("latex","")
        if not latex:
            return
        self.clipboard_clear()
        self.clipboard_append(latex)
        messagebox.showinfo("复制", "LaTeX 源已复制到剪贴板。")

    def render_latex(self):
        if not USE_MATPLOTLIB:
            messagebox.showwarning("渲染不可用", "未安装 matplotlib/Pillow，无法渲染 LaTeX。\n可通过 pip install matplotlib pillow 安装。")
            return
        f = self.formulas[self.current_idx]
        latex = f.get("latex","")
        if not latex:
            return
        # 使用 matplotlib 渲染 LaTeX 到图片
        try:
            fig = plt.figure(figsize=(0.01,0.01))
            fig.text(0, 0, f"${latex}$", fontsize=20)
            fig.patch.set_alpha(0)
            buf = None
            from io import BytesIO
            buf = BytesIO()
            plt.axis("off")
            plt.savefig(buf, format="png", bbox_inches="tight", dpi=150, pad_inches=0.1, transparent=True)
            plt.close(fig)
            buf.seek(0)
            img = Image.open(buf)
            # 可选调整图像大小以适应界面
            maxw, maxh = 700, 200
            w, h = img.size
            scale = min(1.0, maxw / w, maxh / h)
            if scale < 1.0:
                img = img.resize((int(w*scale), int(h*scale)), Image.ANTIALIAS)
            photo = ImageTk.PhotoImage(img)
            self._photo = photo  # 保持引用避免被回收
            self.image_label.config(image=photo)
        except Exception as e:
            messagebox.showerror("渲染失败", f"渲染 LaTeX 失败：{e}")

if __name__ == "__main__":
    app = FormulaApp(formulas)
    app.mainloop()