import os
import json
import io
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
from PIL import Image, ImageTk
import matplotlib.pyplot as plt
import random

# 设置matplotlib支持中文
plt.rcParams['font.sans-serif'] = ['SimHei', 'Microsoft YaHei', 'DejaVu Sans']
plt.rcParams['axes.unicode_minus'] = False

# 数据文件
DATA_FILE = "primary_formulas.json"
FAVORITES_FILE = "favorites.json"

# 小学生公式库
DEFAULT_FORMULAS = [
    {
        "name": "长方形面积",
        "keywords": ["长方形", "面积", "长", "宽"],
        "latex": "S = a \\times b",
        "desc": "长方形的面积 = 长 × 宽",
        "example": "例：长5米，宽3米，面积=5×3=15平方米",
        "grade": "三年级"
    },
    {
        "name": "正方形面积",
        "keywords": ["正方形", "面积", "边长"],
        "latex": "S = a \\times a",
        "desc": "正方形的面积 = 边长 × 边长",
        "example": "例：边长4米，面积=4×4=16平方米",
        "grade": "三年级"
    },
    {
        "name": "长方形周长",
        "keywords": ["长方形", "周长", "长", "宽"],
        "latex": "C = 2 \\times (a + b)",
        "desc": "长方形的周长 = (长 + 宽) × 2",
        "example": "例：长6米，宽4米，周长=(6+4)×2=20米",
        "grade": "三年级"
    },
    {
        "name": "正方形周长",
        "keywords": ["正方形", "周长", "边长"],
        "latex": "C = 4 \\times a",
        "desc": "正方形的周长 = 边长 × 4",
        "example": "例：边长5米，周长=5×4=20米",
        "grade": "三年级"
    },
    {
        "name": "三角形面积",
        "keywords": ["三角形", "面积", "底", "高"],
        "latex": "S = \\frac{1}{2} \\times a \\times h",
        "desc": "三角形的面积 = 底 × 高 ÷ 2",
        "example": "例：底6米，高4米，面积=6×4÷2=12平方米",
        "grade": "五年级"
    },
    {
        "name": "圆的周长",
        "keywords": ["圆", "周长", "半径", "直径"],
        "latex": "C = 2\\pi r",
        "desc": "圆的周长 = 2 × 圆周率 × 半径（π≈3.14）",
        "example": "例：半径5米，周长=2×3.14×5=31.4米",
        "grade": "六年级"
    },
    {
        "name": "圆的面积",
        "keywords": ["圆", "面积", "半径"],
        "latex": "S = \\pi r^2",
        "desc": "圆的面积 = 圆周率 × 半径²（π≈3.14）",
        "example": "例：半径4米，面积=3.14×4×4=50.24平方米",
        "grade": "六年级"
    },
    {
        "name": "加法交换律",
        "keywords": ["加法", "交换律"],
        "latex": "a + b = b + a",
        "desc": "两个数相加，交换位置，和不变",
        "example": "例：3+5=5+3=8",
        "grade": "四年级"
    },
    {
        "name": "乘法交换律",
        "keywords": ["乘法", "交换律"],
        "latex": "a \\times b = b \\times a",
        "desc": "两个数相乘，交换位置，积不变",
        "example": "例：4×7=7×4=28",
        "grade": "四年级"
    },
    {
        "name": "速度公式",
        "keywords": ["速度", "时间", "路程"],
        "latex": "v = \\frac{s}{t}",
        "desc": "速度 = 路程 ÷ 时间",
        "example": "例：3小时行45千米，速度=45÷3=15千米/时",
        "grade": "四年级"
    }
]

def load_data():
    """加载数据"""
    if os.path.exists(DATA_FILE):
        try:
            with open(DATA_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        except:
            pass
    return DEFAULT_FORMULAS.copy()

def save_data(data):
    """保存数据"""
    try:
        with open(DATA_FILE, "w", encoding="utf-8") as f:
            json.dump(data, f, ensure_ascii=False, indent=2)
    except Exception as e:
        print(f"保存失败: {e}")

def load_favorites():
    """加载收藏"""
    if os.path.exists(FAVORITES_FILE):
        try:
            with open(FAVORITES_FILE, "r", encoding="utf-8") as f:
                return json.load(f)
        except:
            pass
    return []

def save_favorites(favorites):
    """保存收藏"""
    try:
        with open(FAVORITES_FILE, "w", encoding="utf-8") as f:
            json.dump(favorites, f, ensure_ascii=False, indent=2)
    except:
        pass

def render_latex(latex_str, dpi=100):
    """渲染LaTeX为图片"""
    try:
        fig = plt.figure(figsize=(0.1, 0.1))
        text = fig.text(0, 0, f"${latex_str}$", fontsize=18)
        fig.subplots_adjust(left=0, right=1, bottom=0, top=1)
        
        buf = io.BytesIO()
        fig.canvas.draw()
        bbox = text.get_window_extent(renderer=fig.canvas.get_renderer())
        width, height = bbox.width / dpi, bbox.height / dpi
        fig.set_size_inches(width + 0.2, height + 0.2)
        fig.canvas.draw()
        fig.savefig(buf, dpi=dpi, format='png', bbox_inches='tight', pad_inches=0.05)
        buf.seek(0)
        img = Image.open(buf)
        img = img.resize((img.width * 2, img.height * 2), Image.Resampling.LANCZOS)
        plt.close(fig)
        return ImageTk.PhotoImage(img)
    except Exception as e:
        print(f"渲染错误: {e}")
        plt.close('all')
        return None

class PrimaryMathApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("🧮 小学生数学公式乐园")
        self.geometry("1000x700")
        self.configure(bg='#E8F5E9')
        
        # 数据
        self.all_data = load_data()
        self.filtered_data = self.all_data.copy()
        self.favorites = load_favorites()
        self.current_item = None
        self.current_image = None
        
        # 创建界面
        self.create_widgets()
        self.populate_list()
        
        # 绑定事件
        self.listbox.bind('<<ListboxSelect>>', self.on_select)
    
    def create_widgets(self):
        """创建界面组件"""
        # 标题
        title_frame = tk.Frame(self, bg='#E8F5E9')
        title_frame.pack(fill=tk.X, padx=10, pady=10)
        
        tk.Label(title_frame, text="📚 小学生数学公式乐园 🎪",
                font=('微软雅黑', 20, 'bold'), bg='#E8F5E9', fg='#FF6B6B').pack()
        tk.Label(title_frame, text="轻松学公式，快乐学数学！",
                font=('微软雅黑', 11), bg='#E8F5E9', fg='#4A90E2').pack()
        
        # 筛选栏
        filter_frame = tk.Frame(self, bg='#E8F5E9')
        filter_frame.pack(fill=tk.X, padx=10, pady=5)
        
        tk.Label(filter_frame, text="年级：", font=('微软雅黑', 10), bg='#E8F5E9').pack(side=tk.LEFT, padx=5)
        self.grade_var = tk.StringVar(value="全部")
        grade_combo = ttk.Combobox(filter_frame, textvariable=self.grade_var,
                                   values=["全部", "三年级", "四年级", "五年级", "六年级"],
                                   width=10, state='readonly')
        grade_combo.pack(side=tk.LEFT, padx=5)
        grade_combo.bind('<<ComboboxSelected>>', lambda e: self.search())
        
        tk.Label(filter_frame, text="搜索：", font=('微软雅黑', 10), bg='#E8F5E9').pack(side=tk.LEFT, padx=(20,5))
        self.search_var = tk.StringVar()
        search_entry = tk.Entry(filter_frame, textvariable=self.search_var, font=('微软雅黑', 10), width=25)
        search_entry.pack(side=tk.LEFT, padx=5)
        search_entry.bind('<Return>', lambda e: self.search())
        
        tk.Button(filter_frame, text="🔍 搜索", command=self.search,
                 bg='#4CAF50', fg='white', font=('微软雅黑', 9)).pack(side=tk.LEFT, padx=5)
        tk.Button(filter_frame, text="⭐ 收藏夹", command=self.show_favorites,
                 bg='#FF9800', fg='white', font=('微软雅黑', 9)).pack(side=tk.LEFT, padx=5)
        tk.Button(filter_frame, text="🎲 随机", command=self.random_formula,
                 bg='#9C27B0', fg='white', font=('微软雅黑', 9)).pack(side=tk.LEFT, padx=5)
        
        # 主区域
        main_pane = tk.PanedWindow(self, orient=tk.HORIZONTAL, bg='#E8F5E9', sashwidth=5)
        main_pane.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        # 左侧列表
        left_frame = tk.Frame(main_pane, bg='white', relief=tk.RAISED, bd=1)
        main_pane.add(left_frame, width=280)
        
        tk.Label(left_frame, text="📖 公式列表", font=('微软雅黑', 12, 'bold'),
                bg='#FFE0B2', fg='#E65100').pack(fill=tk.X)
        
        scrollbar = tk.Scrollbar(left_frame)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        
        self.listbox = tk.Listbox(left_frame, font=('微软雅黑', 11),
                                  yscrollcommand=scrollbar.set,
                                  selectbackground='#FFB74D',
                                  bg='#FFF8E1')
        self.listbox.pack(fill=tk.BOTH, expand=True)
        scrollbar.config(command=self.listbox.yview)
        
        # 右侧详情
        right_frame = tk.Frame(main_pane, bg='white', relief=tk.RAISED, bd=1)
        main_pane.add(right_frame, width=680)
        
        # 标题和按钮
        title_frame2 = tk.Frame(right_frame, bg='#FFF3E0')
        title_frame2.pack(fill=tk.X, padx=15, pady=10)
        
        self.title_label = tk.Label(title_frame2, text="", font=('微软雅黑', 18, 'bold'),
                                    bg='#FFF3E0', fg='#D84315')
        self.title_label.pack(side=tk.LEFT)
        
        btn_frame = tk.Frame(title_frame2, bg='#FFF3E0')
        btn_frame.pack(side=tk.RIGHT)
        
        self.fav_btn = tk.Button(btn_frame, text="⭐ 收藏", command=self.toggle_favorite,
                                 font=('微软雅黑', 10), bg='#FFD54F')
        self.fav_btn.pack(side=tk.LEFT, padx=5)
        
        tk.Button(btn_frame, text="📋 复制", command=self.copy_latex,
                 font=('微软雅黑', 10), bg='#81C784').pack(side=tk.LEFT, padx=5)
        
        # 年级标签
        self.grade_label = tk.Label(right_frame, text="", font=('微软雅黑', 10, 'bold'),
                                    bg='#E3F2FD', fg='#1565C0', padx=10, pady=2)
        self.grade_label.pack(anchor=tk.W, padx=15, pady=5)
        
        # 公式图片
        self.canvas_label = tk.Label(right_frame, bg='#F5F5F5', relief=tk.SUNKEN)
        self.canvas_label.pack(padx=15, pady=10, fill=tk.BOTH, expand=True)
        
        # 说明
        desc_frame = tk.Frame(right_frame, bg='#FCE4EC', relief=tk.GROOVE, bd=1)
        desc_frame.pack(fill=tk.X, padx=15, pady=10)
        
        tk.Label(desc_frame, text="📝 公式说明：", font=('微软雅黑', 11, 'bold'),
                bg='#FCE4EC', fg='#C2185B').pack(anchor=tk.W, padx=10, pady=5)
        
        self.desc_label = tk.Label(desc_frame, text="", wraplength=600,
                                   justify=tk.LEFT, font=('微软雅黑', 10), bg='#FCE4EC')
        self.desc_label.pack(anchor=tk.W, padx=10, pady=5)
        
        # 例题
        example_frame = tk.Frame(right_frame, bg='#E8EAF6', relief=tk.GROOVE, bd=1)
        example_frame.pack(fill=tk.X, padx=15, pady=10)
        
        tk.Label(example_frame, text="🎯 例题解析：", font=('微软雅黑', 11, 'bold'),
                bg='#E8EAF6', fg='#283593').pack(anchor=tk.W, padx=10, pady=5)
        
        self.example_label = tk.Label(example_frame, text="", wraplength=600,
                                      justify=tk.LEFT, font=('微软雅黑', 10), bg='#E8EAF6')
        self.example_label.pack(anchor=tk.W, padx=10, pady=5)
        
        # 底部按钮
        bottom_frame = tk.Frame(self, bg='#E8F5E9')
        bottom_frame.pack(fill=tk.X, padx=10, pady=10)
        
        tk.Button(bottom_frame, text="🎮 开始测验", command=self.start_quiz,
                 font=('微软雅黑', 11, 'bold'), bg='#FF9800', fg='white', padx=20, pady=5).pack(side=tk.LEFT, padx=10)
        tk.Button(bottom_frame, text="📊 学习统计", command=self.show_stats,
                 font=('微软雅黑', 11, 'bold'), bg='#00BCD4', fg='white', padx=20, pady=5).pack(side=tk.LEFT, padx=10)
    
    def populate_list(self):
        """填充列表"""
        self.listbox.delete(0, tk.END)
        grade_emoji = {"三年级": "🐣", "四年级": "🐥", "五年级": "🦊", "六年级": "🦁"}
        for item in self.filtered_data:
            emoji = grade_emoji.get(item.get("grade", ""), "📐")
            self.listbox.insert(tk.END, f"{emoji} {item['name']}")
    
    def search(self):
        """搜索"""
        query = self.search_var.get().strip().lower()
        grade = self.grade_var.get()
        
        results = []
        for item in self.all_data:
            if grade != "全部" and item.get("grade") != grade:
                continue
            if query:
                if (query in item["name"].lower() or
                    query in item.get("desc", "").lower() or
                    any(query in kw.lower() for kw in item.get("keywords", []))):
                    results.append(item)
            else:
                results.append(item)
        
        self.filtered_data = results
        self.populate_list()
    
    def on_select(self, event=None):
        """选择公式"""
        selection = self.listbox.curselection()
        if not selection:
            return
        
        # 获取公式名（去掉表情符号）
        text = self.listbox.get(selection[0])
        name = text.split(' ', 1)[-1] if ' ' in text else text
        
        # 查找公式
        for item in self.filtered_data:
            if item["name"] == name:
                self.current_item = item
                break
        
        if not self.current_item:
            return
        
        # 更新显示
        self.title_label.config(text=self.current_item["name"])
        self.desc_label.config(text=self.current_item.get("desc", ""))
        self.example_label.config(text=self.current_item.get("example", "暂无例题"))
        self.grade_label.config(text=f"📚 年级：{self.current_item.get('grade', '未标注')}")
        
        # 更新收藏按钮
        if self.current_item["name"] in self.favorites:
            self.fav_btn.config(text="❤️ 已收藏", bg='#EF5350')
        else:
            self.fav_btn.config(text="⭐ 收藏", bg='#FFD54F')
        
        # 渲染公式
        self.update_formula_image()
    
    def update_formula_image(self):
        """更新公式图片"""
        if not self.current_item:
            return
        
        latex_str = self.current_item.get("latex", "")
        if latex_str:
            img = render_latex(latex_str)
            if img:
                self.current_image = img
                self.canvas_label.config(image=img, text="")
            else:
                self.canvas_label.config(image="", text="公式预览失败")
        else:
            self.canvas_label.config(image="", text="无公式")
    
    def toggle_favorite(self):
        """切换收藏"""
        if not self.current_item:
            messagebox.showinfo("提示", "请先选择一个公式")
            return
        
        name = self.current_item["name"]
        if name in self.favorites:
            self.favorites.remove(name)
            self.fav_btn.config(text="⭐ 收藏", bg='#FFD54F')
            messagebox.showinfo("成功", f"已移除「{name}」")
        else:
            self.favorites.append(name)
            self.fav_btn.config(text="❤️ 已收藏", bg='#EF5350')
            messagebox.showinfo("成功", f"已收藏「{name}」")
        
        save_favorites(self.favorites)
    
    def copy_latex(self):
        """复制LaTeX"""
        if self.current_item:
            self.clipboard_clear()
            self.clipboard_append(self.current_item.get("latex", ""))
            messagebox.showinfo("成功", "✓ 已复制到剪贴板")
        else:
            messagebox.showinfo("提示", "请先选择一个公式")
    
    def random_formula(self):
        """随机公式"""
        if not self.filtered_data:
            messagebox.showinfo("提示", "没有公式")
            return
        
        item = random.choice(self.filtered_data)
        for i in range(self.listbox.size()):
            if item["name"] in self.listbox.get(i):
                self.listbox.selection_clear(0, tk.END)
                self.listbox.selection_set(i)
                self.listbox.see(i)
                self.on_select()
                break
    
    def show_favorites(self):
        """显示收藏"""
        if not self.favorites:
            messagebox.showinfo("收藏夹", "还没有收藏任何公式")
            return
        
        self.filtered_data = [item for item in self.all_data if item["name"] in self.favorites]
        self.populate_list()
        self.grade_var.set("全部")
        self.search_var.set("")
        messagebox.showinfo("收藏夹", f"找到 {len(self.filtered_data)} 个收藏公式")
    
    def start_quiz(self):
        """开始测验"""
        if len(self.all_data) < 3:
            messagebox.showinfo("提示", "公式太少，需要至少3个")
            return
        
        # 创建测验窗口
        quiz_win = tk.Toplevel(self)
        quiz_win.title("公式测验")
        quiz_win.geometry("500x500")
        quiz_win.configure(bg='#FFF9C4')
        
        # 选择题目
        questions = random.sample(self.all_data, min(5, len(self.all_data)))
        self.quiz_data = {
            'questions': questions,
            'current': 0,
            'score': 0,
            'window': quiz_win
        }
        
        self.show_quiz_question()
    
    def show_quiz_question(self):
        """显示测验题目"""
        quiz_win = self.quiz_data['window']
        current = self.quiz_data['current']
        questions = self.quiz_data['questions']
        
        # 清空窗口
        for widget in quiz_win.winfo_children():
            widget.destroy()
        
        if current >= len(questions):
            # 结束
            tk.Label(quiz_win, text=f"测验结束！\n得分：{self.quiz_data['score']}/{len(questions)}",
                    font=('微软雅黑', 18, 'bold'), bg='#FFF9C4', fg='#FF6F00').pack(expand=True)
            tk.Button(quiz_win, text="关闭", command=quiz_win.destroy,
                     font=('微软雅黑', 12), bg='#4CAF50', fg='white', padx=20).pack(pady=20)
            return
        
        q = questions[current]
        
        # 显示进度
        tk.Label(quiz_win, text=f"第 {current+1}/{len(questions)} 题",
                font=('微软雅黑', 14), bg='#FFF9C4').pack(pady=10)
        
        # 显示公式
        tk.Label(quiz_win, text="这个公式的名称是？",
                font=('微软雅黑', 16), bg='#FFF9C4').pack(pady=10)
        
        img = render_latex(q.get("latex", ""))
        if img:
            img_label = tk.Label(quiz_win, image=img, bg='#FFF9C4')
            img_label.image = img
            img_label.pack(pady=20)
        
        # 选项
        options = [q["name"]]
        others = [f["name"] for f in self.all_data if f["name"] != q["name"]]
        if len(others) >= 3:
            options.extend(random.sample(others, 3))
        random.shuffle(options)
        
        for opt in options:
            tk.Button(quiz_win, text=opt, command=lambda o=opt: self.check_answer(o),
                     font=('微软雅黑', 11), bg='#66BB6A', fg='white', padx=20, pady=8).pack(pady=5)
    
    def check_answer(self, selected):
        """检查答案"""
        questions = self.quiz_data['questions']
        current = self.quiz_data['current']
        correct = questions[current]["name"]
        
        if selected == correct:
            self.quiz_data['score'] += 1
            messagebox.showinfo("✓ 正确", f"答对了！")
        else:
            messagebox.showinfo("✗ 错误", f"正确答案：{correct}")
        
        self.quiz_data['current'] += 1
        self.show_quiz_question()
    
    def show_stats(self):
        """显示统计"""
        stats_win = tk.Toplevel(self)
        stats_win.title("学习统计")
        stats_win.geometry("400x350")
        stats_win.configure(bg='#E0F7FA')
        
        # 统计
        grade_count = {}
        for item in self.all_data:
            grade = item.get("grade", "未分类")
            grade_count[grade] = grade_count.get(grade, 0) + 1
        
        text = f"📊 学习统计\n\n总公式数：{len(self.all_data)}\n收藏公式：{len(self.favorites)}\n收藏率：{len(self.favorites)/len(self.all_data)*100:.1f}%\n\n各年级分布：\n"
        for grade, count in grade_count.items():
            text += f"  {grade}：{count}个\n"
        
        tk.Label(stats_win, text=text, font=('微软雅黑', 11),
                bg='#E0F7FA', justify=tk.LEFT).pack(padx=30, pady=30)
        tk.Button(stats_win, text="关闭", command=stats_win.destroy,
                 font=('微软雅黑', 10), bg='#4CAF50', fg='white').pack(pady=10)

if __name__ == "__main__":
    app = PrimaryMathApp()
    app.mainloop()