import tkinter as tk
from tkinter import ttk, messagebox, scrolledtext
import json
import os
import urllib.request
import urllib.parse
import threading

# 数据文件名
DATA_FILE = "my_math_formulas.json"


class ZeroDepMathApp:
    def __init__(self, root):
        self.root = root
        # 修改标题：去除了 Emoji
        self.root.title("数学公式查询 (零依赖版)")
        self.root.geometry("800x550")

        # 设置高DPI支持 (Windows)
        try:
            from ctypes import windll
            windll.shcore.SetProcessDpiAwareness(1)
        except:
            pass

        # 1. 加载数据
        self.formulas = self.load_data()

        # 创建界面
        self.create_ui()

    def load_data(self):
        """从本地JSON加载数据，如果没有则创建默认数据"""
        default_data = {
            "勾股定理": "a^2 + b^2 = c^2 (直角三角形)",
            "一元二次方程": "x = (-b +/- sqrt(b^2 - 4ac)) / 2a",
            "圆的面积": "S = pi * r^2",
            "圆的周长": "C = 2 * pi * r",
            "三角函数正弦": "sin(theta) = 对边 / 斜边",
            "欧拉公式": "e^(i*pi) + 1 = 0",
            "导数定义": "f'(x) = lim(h->0) [f(x+h) - f(x)] / h",
            "贝叶斯定理": "P(A|B) = [P(B|A) * P(A)] / P(B)",
            "球体体积": "V = (4/3) * pi * r^3",
            "等差数列求和": "Sn = n(a1 + an) / 2"
        }

        if os.path.exists(DATA_FILE):
            try:
                with open(DATA_FILE, 'r', encoding='utf-8') as f:
                    data = json.load(f)
                    print(f"已加载 {len(data)} 条本地公式。")
                    return data
            except:
                pass

        # 首次运行保存默认数据
        self.save_data(default_data)
        return default_data

    def save_data(self, data=None):
        """保存数据到本地JSON"""
        if data is None:
            data = self.formulas
        try:
            with open(DATA_FILE, 'w', encoding='utf-8') as f:
                json.dump(data, f, ensure_ascii=False, indent=4)
            return True
        except Exception as e:
            print(f"保存失败: {e}")
            return False

    def create_ui(self):
        # --- 布局配置 ---
        self.root.columnconfigure(1, weight=1)
        self.root.rowconfigure(1, weight=1)

        # === 左侧面板 (搜索与列表) ===
        left_frame = tk.Frame(self.root, bg="#f0f0f0", width=250)
        left_frame.grid(row=0, column=0, rowspan=2,
                        sticky="ns", padx=0, pady=0)
        left_frame.pack_propagate(False)  # 固定宽度

        # 标题 (去除 Emoji)
        tk.Label(left_frame, text="搜索公式", font=("Microsoft YaHei",
                 16, "bold"), bg="#f0f0f0").pack(pady=(20, 10))

        # 搜索框
        self.search_entry = tk.Entry(
            left_frame, font=("Arial", 12), justify='center')
        self.search_entry.pack(padx=15, pady=5, fill=tk.X)
        self.search_entry.bind("<Return>", lambda e: self.search_local())

        # 按钮区域
        btn_frame = tk.Frame(left_frame, bg="#f0f0f0")
        btn_frame.pack(padx=15, pady=10, fill=tk.X)

        tk.Button(btn_frame, text="本地查询", command=self.search_local, bg="#dddddd",
                  activebackground="#cccccc").pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(0, 5))
        # 修改按钮文字：去除 Emoji
        tk.Button(btn_frame, text="联网搜索", command=self.start_web_search, bg="#4a90e2", fg="white",
                  activebackground="#357abd").pack(side=tk.LEFT, expand=True, fill=tk.X, padx=(5, 0))

        # 修改按钮文字：去除 Emoji
        tk.Button(left_frame, text="+ 添加新公式", command=self.add_formula_dialog,
                  bg="#eeeeee").pack(padx=15, pady=5, fill=tk.X)

        # 列表区域
        list_frame = tk.Frame(left_frame, bg="white")
        list_frame.pack(padx=15, pady=10, fill=tk.BOTH, expand=True)

        tk.Label(list_frame, text="结果列表:", bg="white",
                 anchor="w").pack(fill=tk.X)

        self.listbox = tk.Listbox(list_frame, font=(
            "Arial", 11), selectmode=tk.SINGLE, borderwidth=0, highlightthickness=0)
        self.listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)

        scrollbar = ttk.Scrollbar(
            list_frame, orient=tk.VERTICAL, command=self.listbox.yview)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.listbox.config(yscrollcommand=scrollbar.set)
        self.listbox.bind('<<ListboxSelect>>', self.on_select)

        # 初始化列表
        self.update_listbox(list(self.formulas.keys()))

        # === 右侧面板 (详情展示) ===
        right_frame = tk.LabelFrame(self.root, text="详细内容", font=(
            "Microsoft YaHei", 12, "bold"), padx=10, pady=10)
        right_frame.grid(row=0, column=1, rowspan=2,
                         padx=20, pady=20, sticky="nsew")
        right_frame.columnconfigure(0, weight=1)
        right_frame.rowconfigure(0, weight=1)

        # 标题标签
        self.detail_title = tk.Label(right_frame, text="欢迎使用", font=(
            "Microsoft YaHei", 18, "bold"), anchor="w")
        self.detail_title.pack(fill=tk.X, pady=(0, 10))

        # 文本显示区 (只读)
        self.detail_text = scrolledtext.ScrolledText(right_frame, font=(
            "Consolas", 14), wrap=tk.WORD, state=tk.DISABLED, bg="#fafafa")
        self.detail_text.pack(fill=tk.BOTH, expand=True)

        # 底部按钮 (去除 Emoji)
        bottom_frame = tk.Frame(right_frame, bg="white")
        bottom_frame.pack(fill=tk.X, pady=(10, 0))
        tk.Button(bottom_frame, text="复制内容",
                  command=self.copy_content).pack(side=tk.RIGHT)

    def update_listbox(self, items):
        self.listbox.delete(0, tk.END)
        for item in items:
            self.listbox.insert(tk.END, item)

    def search_local(self):
        keyword = self.search_entry.get().strip().lower()
        if not keyword:
            self.update_listbox(list(self.formulas.keys()))
            self.show_message("所有公式", "请在左侧列表中点击查看详情。")
            return

        matches = [name for name in self.formulas.keys()
                   if keyword in name.lower()]
        self.update_listbox(matches)

        if matches:
            self.show_message(f"找到 {len(matches)} 条结果", "请点击列表查看详情。")
        else:
            # 修改提示文字：去除 Emoji
            self.show_message("未找到本地结果", "提示：试试点击上方的【联网搜索】按钮查找网络资源。")

    def on_select(self, event):
        selection = self.listbox.curselection()
        if selection:
            index = selection[0]
            name = self.listbox.get(index)
            content = self.formulas.get(name, "无内容")
            self.show_message(name, content)

    def show_message(self, title, content):
        self.detail_title.config(text=title)
        self.detail_text.config(state=tk.NORMAL)
        self.detail_text.delete("1.0", tk.END)
        self.detail_text.insert(tk.END, content)
        self.detail_text.config(state=tk.DISABLED)

    def start_web_search(self):
        keyword = self.search_entry.get().strip()
        if not keyword:
            messagebox.showwarning("提示", "请先输入要搜索的数学概念！")
            return

        self.detail_title.config(text=f"正在联网搜索：{keyword}...")
        self.detail_text.config(state=tk.NORMAL)
        self.detail_text.delete("1.0", tk.END)
        # 修改提示文字：去除 Emoji
        self.detail_text.insert(
            tk.END, "正在连接维基百科服务器，请稍候...\n(如果长时间无反应，请检查网络连接)")
        self.detail_text.config(state=tk.DISABLED)

        # 使用线程避免界面卡死
        thread = threading.Thread(target=self.fetch_wiki, args=(keyword,))
        thread.daemon = True
        thread.start()

    def fetch_wiki(self, keyword):
        try:
            # 编码关键词
            url_keyword = urllib.parse.quote(keyword)
            url = f"https://zh.wikipedia.org/w/api.php?action=query&format=json&prop=extracts&exintro&explaintext&titles={url_keyword}"

            # 构建请求头 (模拟浏览器)
            headers = {
                'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) MathApp/1.0'}
            req = urllib.request.Request(url, headers=headers)

            with urllib.request.urlopen(req, timeout=10) as response:
                data = response.read().decode('utf-8')
                json_data = json.loads(data)

                pages = json_data['query']['pages']
                page_id = next(iter(pages))

                result = ""
                if page_id == "-1":
                    # 修改提示文字：去除 Emoji
                    result = f"未在维基百科找到关于 '{keyword}' 的条目。\n可能是关键词不准确，或者该概念没有独立的百科页面。\n\n建议尝试更换关键词，例如：\n- 将 '勾股' 改为 '勾股定理'\n- 将 '微积分' 改为 '微积分基本定理'"
                else:
                    title = pages[page_id]['title']
                    extract = pages[page_id].get('extract', '无摘要内容。')
                    # 修改格式符号：去除 Emoji
                    result = f"来源：维基百科 ({title})\n\n{'='*30}\n\n{extract}\n\n{'='*30}\n(注：此为简要介绍)"

                # 更新UI
                self.root.after(0, lambda: self.show_message(
                    f"联网结果：{keyword}", result))

        except Exception as e:
            # 修改错误提示：去除 Emoji
            error_msg = f"网络请求失败:\n{str(e)}\n\n请检查：\n1. 网络连接是否正常\n2. 是否能访问维基百科"
            self.root.after(0, lambda: self.show_message("搜索错误", error_msg))

    def copy_content(self):
        content = self.detail_text.get("1.0", tk.END).strip()
        if not content or "正在连接" in content or "欢迎使用" in self.detail_title.cget("text"):
            messagebox.showinfo("提示", "没有可复制的有效内容。")
            return

        self.root.clipboard_clear()
        self.root.clipboard_append(content)
        # 修改提示：去除 Emoji
        messagebox.showinfo("成功", "内容已复制到剪贴板！")

    def add_formula_dialog(self):
        dialog = tk.Toplevel(self.root)
        dialog.title("添加新公式")
        dialog.geometry("400x250")
        dialog.transient(self.root)
        dialog.grab_set()

        tk.Label(dialog, text="公式名称:", font=("Arial", 11)).pack(pady=(15, 5))
        name_entry = tk.Entry(dialog, width=40, font=("Arial", 12))
        name_entry.pack(pady=5)

        tk.Label(dialog, text="公式内容:", font=("Arial", 11)).pack(pady=(10, 5))
        content_entry = tk.Entry(dialog, width=40, font=("Arial", 12))
        content_entry.pack(pady=5)

        def save():
            name = name_entry.get().strip()
            content = content_entry.get().strip()
            if name and content:
                self.formulas[name] = content
                if self.save_data():
                    self.update_listbox(list(self.formulas.keys()))
                    self.show_message(name, content)
                    messagebox.showinfo("成功", "公式已添加并保存！")
                    dialog.destroy()
                else:
                    messagebox.showerror("错误", "保存文件失败。")
            else:
                messagebox.showwarning("警告", "名称和内容不能为空！")

        tk.Button(dialog, text="保存", command=save, bg="#4CAF50",
                  fg="white", font=("Arial", 11, "bold")).pack(pady=20)


if __name__ == "__main__":
    root = tk.Tk()
    app = ZeroDepMathApp(root)
    root.mainloop()
