import pygame
import sys
import math
import json
import os
from collections import defaultdict

# 初始化 Pygame
pygame.init()

# 窗口设置
WIDTH, HEIGHT = 1200, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("数学公式查询系统 - Math Formula Encyclopedia")

# 颜色定义
COLORS = {
    "bg": (240, 245, 250),          # 背景色
    "primary": (30, 136, 229),      # 主色
    "secondary": (0, 150, 136),     # 次要色
    "accent": (255, 87, 34),        # 强调色
    "text": (33, 33, 33),          # 文字
    "text_light": (117, 117, 117), # 浅色文字
    "white": (255, 255, 255),      # 白色
    "card": (255, 255, 255),       # 卡片
    "sidebar": (30, 30, 40),       # 侧边栏
    "hover": (245, 245, 245),      # 悬停
    "success": (76, 175, 80),      # 成功色
    "warning": (255, 193, 7),      # 警告色
    "error": (244, 67, 54),        # 错误色
    "category_algebra": (66, 165, 245),    # 代数
    "category_geometry": (102, 187, 106),  # 几何
    "category_trig": (171, 71, 188),       # 三角
    "category_calculus": (255, 152, 0),    # 微积分
    "category_stats": (121, 85, 72),       # 统计
    "search_bg": (255, 255, 255),         # 搜索框
    "shadow": (0, 0, 0, 30)               # 阴影
}

# 加载字体
def load_font(size, bold=False):
    """加载字体，支持中英文"""
    try:
        # 尝试加载中文字体
        font_path = None
        for font_name in ["msyh.ttc", "simhei.ttf", "arial.ttf"]:
            if os.path.exists(font_name):
                font_path = font_name
                break
        
        if font_path and font_path.endswith('.ttc'):
            # 对于.ttc字体集合，需要指定索引
            return pygame.font.Font(font_path, size)
        elif font_path:
            return pygame.font.Font(font_path, size)
        else:
            # 使用系统默认字体
            return pygame.font.SysFont(None, size, bold=bold)
    except:
        return pygame.font.SysFont(None, size, bold=bold)

# 创建字体实例
title_font = load_font(36, True)
heading_font = load_font(28, True)
subtitle_font = load_font(24)
body_font = load_font(20)
small_font = load_font(16)
formula_font = load_font(32, True)  # 公式字体

# 数学公式数据库
MATHEMATICS_FORMULAS = {
    "algebra": {
        "name": "代数",
        "icon": "𝑥²",
        "color": COLORS["category_algebra"],
        "formulas": [
            {
                "name": "二次方程求根公式",
                "symbol": "x = (-b ± √(b² - 4ac)) / 2a",
                "description": "用于求解一元二次方程 ax² + bx + c = 0 的根",
                "variables": [
                    {"symbol": "a", "name": "二次项系数"},
                    {"symbol": "b", "name": "一次项系数"},
                    {"symbol": "c", "name": "常数项"},
                    {"symbol": "Δ", "name": "判别式 Δ = b² - 4ac"}
                ],
                "example": "方程 2x² + 3x - 2 = 0 的解为 x = 0.5 或 x = -2"
            },
            {
                "name": "因式分解公式",
                "symbol": "(a + b)² = a² + 2ab + b²",
                "description": "完全平方和公式，是基本的代数恒等式",
                "variations": [
                    "(a - b)² = a² - 2ab + b²",
                    "a² - b² = (a + b)(a - b)",
                    "(a + b)³ = a³ + 3a²b + 3ab² + b³"
                ],
                "example": "(x + 3)² = x² + 6x + 9"
            },
            {
                "name": "等差数列求和",
                "symbol": "S_n = n(a₁ + a_n) / 2 = n[2a₁ + (n-1)d] / 2",
                "description": "计算等差数列前n项的和",
                "variables": [
                    {"symbol": "S_n", "name": "前n项和"},
                    {"symbol": "a₁", "name": "首项"},
                    {"symbol": "a_n", "name": "第n项"},
                    {"symbol": "n", "name": "项数"},
                    {"symbol": "d", "name": "公差"}
                ],
                "example": "数列 1, 3, 5, 7, 9 的前5项和 S₅ = 25"
            }
        ]
    },
    "geometry": {
        "name": "几何",
        "icon": "△",
        "color": COLORS["category_geometry"],
        "formulas": [
            {
                "name": "勾股定理",
                "symbol": "c² = a² + b²",
                "description": "直角三角形斜边与两直角边的关系",
                "variables": [
                    {"symbol": "c", "name": "斜边（hypotenuse）"},
                    {"symbol": "a, b", "name": "直角边（legs）"}
                ],
                "example": "直角边为3和4，则斜边c = √(3²+4²) = 5"
            },
            {
                "name": "圆面积公式",
                "symbol": "S = πr²",
                "description": "计算圆的面积，π是圆周率≈3.14159",
                "variables": [
                    {"symbol": "S", "name": "圆面积"},
                    {"symbol": "r", "name": "半径"},
                    {"symbol": "π", "name": "圆周率 ≈ 3.14159"}
                ],
                "example": "半径为5的圆面积 S = 25π ≈ 78.54"
            }
        ]
    }
}

class Button:
    """按钮类"""
    def __init__(self, x, y, width, height, text, action=None, color=None, text_color=COLORS["white"]):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.action = action
        self.color = color or COLORS["primary"]
        self.text_color = text_color
        self.hover = False
        self.active = False
        self.radius = 8
        
    def draw(self, surface):
        # 绘制按钮背景
        current_color = self.color
        if self.hover:
            # 悬停时变浅
            current_color = tuple(min(c + 20, 255) for c in self.color[:3])
        
        pygame.draw.rect(surface, current_color, self.rect, border_radius=self.radius)
        
        # 绘制按钮边框
        border_color = tuple(max(c - 30, 0) for c in current_color[:3])
        pygame.draw.rect(surface, border_color, self.rect, 2, border_radius=self.radius)
        
        # 绘制按钮文字
        font = subtitle_font if self.rect.height > 40 else small_font
        text_surface = font.render(self.text, True, self.text_color)
        text_rect = text_surface.get_rect(center=self.rect.center)
        surface.blit(text_surface, text_rect)
        
    def check_hover(self, pos):
        self.hover = self.rect.collidepoint(pos)
        return self.hover
        
    def handle_click(self, pos):
        if self.rect.collidepoint(pos) and self.action:
            return self.action()
        return False

class CategoryCard:
    """分类卡片类"""
    def __init__(self, x, y, width, height, category_key, category_data):
        self.rect = pygame.Rect(x, y, width, height)
        self.category_key = category_key
        self.category_data = category_data
        self.hover = False
        self.active = False
        
    def draw(self, surface):
        # 绘制卡片背景
        bg_color = self.category_data["color"]
        if self.hover:
            bg_color = tuple(min(c + 20, 255) for c in bg_color[:3])
        if self.active:
            bg_color = tuple(min(c + 30, 255) for c in bg_color[:3])
            
        pygame.draw.rect(surface, bg_color, self.rect, border_radius=12)
        
        # 绘制图标
        icon_font = load_font(48, True)
        icon_surface = icon_font.render(self.category_data["icon"], True, COLORS["white"])
        icon_rect = icon_surface.get_rect(center=(self.rect.centerx, self.rect.centery - 20))
        surface.blit(icon_surface, icon_rect)
        
        # 绘制分类名称
        name_surface = subtitle_font.render(self.category_data["name"], True, COLORS["white"])
        name_rect = name_surface.get_rect(center=(self.rect.centerx, self.rect.centery + 20))
        surface.blit(name_surface, name_rect)
        
        # 绘制公式数量
        count = len(self.category_data["formulas"])
        count_text = f"{count} 个公式"
        count_surface = small_font.render(count_text, True, COLORS["white"])
        count_rect = count_surface.get_rect(center=(self.rect.centerx, self.rect.centery + 50))
        surface.blit(count_surface, count_rect)
        
    def check_hover(self, pos):
        self.hover = self.rect.collidepoint(pos)
        return self.hover

class FormulaCard:
    """公式卡片类"""
    def __init__(self, x, y, width, height, formula_data, index):
        self.rect = pygame.Rect(x, y, width, height)
        self.formula_data = formula_data
        self.index = index
        self.hover = False
        
    def draw(self, surface):
        # 绘制卡片背景
        bg_color = COLORS["card"]
        if self.hover:
            bg_color = tuple(min(c + 10, 255) for c in bg_color[:3])
            
        pygame.draw.rect(surface, bg_color, self.rect, border_radius=10)
        
        # 绘制边框
        border_color = tuple(max(c - 20, 200) for c in bg_color[:3])
        pygame.draw.rect(surface, border_color, self.rect, 2, border_radius=10)
        
        # 绘制序号
        index_surface = subtitle_font.render(f"{self.index}.", True, COLORS["primary"])
        surface.blit(index_surface, (self.rect.x + 20, self.rect.y + 20))
        
        # 绘制公式名称
        name_surface = subtitle_font.render(self.formula_data["name"], True, COLORS["text"])
        surface.blit(name_surface, (self.rect.x + 60, self.rect.y + 20))
        
        # 绘制公式符号
        formula_text = self.formula_data["symbol"]
        formula_surface = formula_font.render(formula_text, True, COLORS["accent"])
        formula_rect = formula_surface.get_rect()
        formula_rect.midleft = (self.rect.x + 30, self.rect.centery)
        surface.blit(formula_surface, formula_rect)
        
        # 绘制描述
        if "description" in self.formula_data:
            desc = self.formula_data["description"]
            if len(desc) > 40:
                desc = desc[:40] + "..."
            desc_surface = small_font.render(desc, True, COLORS["text_light"])
            surface.blit(desc_surface, (self.rect.x + 30, self.rect.bottom - 40))
        
    def check_hover(self, pos):
        self.hover = self.rect.collidepoint(pos)
        return self.hover

class SearchBox:
    """搜索框类"""
    def __init__(self, x, y, width, height):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = ""
        self.active = False
        self.cursor_visible = True
        self.cursor_timer = 0
        self.hover = False  # 添加hover属性
        
    def draw(self, surface):
        # 绘制搜索框背景
        bg_color = COLORS["search_bg"]
        if self.active:
            bg_color = tuple(min(c + 20, 255) for c in bg_color[:3])
        elif self.hover:
            bg_color = tuple(min(c + 10, 255) for c in bg_color[:3])
            
        pygame.draw.rect(surface, bg_color, self.rect, border_radius=8)
        pygame.draw.rect(surface, COLORS["primary"], self.rect, 2, border_radius=8)
        
        # 绘制搜索图标
        search_icon = body_font.render("🔍", True, COLORS["text_light"])
        surface.blit(search_icon, (self.rect.x + 15, self.rect.centery - 10))
        
        # 绘制文本
        text_surface = body_font.render(self.text, True, COLORS["text"])
        text_rect = text_surface.get_rect(midleft=(self.rect.x + 50, self.rect.centery))
        surface.blit(text_surface, text_rect)
        
        # 绘制占位符
        if not self.text and not self.active:
            placeholder = small_font.render("输入公式名称或关键词...", True, COLORS["text_light"])
            surface.blit(placeholder, (self.rect.x + 50, self.rect.centery - 8))
        
        # 绘制光标
        if self.active and self.cursor_visible:
            cursor_x = self.rect.x + 50 + text_surface.get_width()
            pygame.draw.line(surface, COLORS["text"], 
                           (cursor_x, self.rect.y + 10),
                           (cursor_x, self.rect.bottom - 10), 2)
    
    def update(self, dt):
        """更新光标闪烁"""
        self.cursor_timer += dt
        if self.cursor_timer > 500:  # 500ms闪烁一次
            self.cursor_visible = not self.cursor_visible
            self.cursor_timer = 0
    
    def check_hover(self, pos):
        """检查鼠标是否悬停"""
        self.hover = self.rect.collidepoint(pos)
        return self.hover
    
    def handle_event(self, event):
        if event.type == pygame.KEYDOWN and self.active:
            if event.key == pygame.K_RETURN:
                return self.text
            elif event.key == pygame.K_BACKSPACE:
                self.text = self.text[:-1]
            elif event.key == pygame.K_ESCAPE:
                self.active = False
            else:
                if len(self.text) < 30:  # 限制输入长度
                    self.text += event.unicode
        elif event.type == pygame.MOUSEBUTTONDOWN:
            self.active = self.rect.collidepoint(event.pos)
        
        return None

class MathFormulaApp:
    """数学公式查询应用"""
    def __init__(self):
        self.current_category = "algebra"
        self.selected_formula = None
        self.search_results = []
        self.search_mode = False
        
        # 创建分类卡片
        self.category_cards = []
        x_start = 350
        y_start = 100
        card_width = 150
        card_height = 150
        margin = 20
        
        categories = list(MATHEMATICS_FORMULAS.keys())
        for i, cat_key in enumerate(categories):
            row = i // 3
            col = i % 3
            x = x_start + col * (card_width + margin)
            y = y_start + row * (card_height + margin)
            
            card = CategoryCard(x, y, card_width, card_height, 
                              cat_key, MATHEMATICS_FORMULAS[cat_key])
            self.category_cards.append(card)
        
        # 创建搜索框
        self.search_box = SearchBox(350, 50, 500, 40)
        
        # 创建返回按钮
        self.back_button = Button(20, 20, 100, 40, "← 返回", 
                                lambda: setattr(self, 'selected_formula', None))
        
        # 创建控制按钮
        self.control_buttons = [
            Button(WIDTH - 150, HEIGHT - 100, 120, 40, "随机公式", self.random_formula),
            Button(WIDTH - 150, HEIGHT - 50, 120, 40, "重置搜索", self.reset_search)
        ]
        
        # 创建公式卡片列表
        self.formula_cards = []
        
    def draw_sidebar(self, surface):
        """绘制侧边栏"""
        sidebar_width = 300
        pygame.draw.rect(surface, COLORS["sidebar"], (0, 0, sidebar_width, HEIGHT))
        
        # 绘制标题
        title = title_font.render("数学公式", True, COLORS["white"])
        subtitle = subtitle_font.render("百科全书", True, COLORS["success"])
        surface.blit(title, (30, 30))
        surface.blit(subtitle, (30, 80))
        
        # 绘制统计信息
        total_formulas = sum(len(cat["formulas"]) for cat in MATHEMATICS_FORMULAS.values())
        stats_text = [
            f"公式总数: {total_formulas}",
            f"分类数量: {len(MATHEMATICS_FORMULAS)}",
            "最新更新: 2024-12-01"
        ]
        
        for i, text in enumerate(stats_text):
            stat_surface = small_font.render(text, True, COLORS["white"])
            surface.blit(stat_surface, (30, 150 + i * 30))
        
        # 绘制使用说明
        instructions = [
            "使用说明:",
            "1. 点击分类查看公式",
            "2. 点击公式查看详情",
            "3. 搜索框输入关键词",
            "4. 使用ESC键返回"
        ]
        
        for i, text in enumerate(instructions):
            inst_surface = small_font.render(text, True, COLORS["white"])
            surface.blit(inst_surface, (30, 300 + i * 30))
        
        # 绘制版权信息
        copyright_text = "© 2024 数学公式查询系统"
        copyright_surface = small_font.render(copyright_text, True, COLORS["text_light"])
        surface.blit(copyright_surface, (30, HEIGHT - 50))
    
    def draw_formula_detail(self, surface, formula_data):
        """绘制公式详情页"""
        if not formula_data:
            return
            
        # 绘制背景卡片
        detail_rect = pygame.Rect(320, 100, WIDTH - 340, HEIGHT - 120)
        pygame.draw.rect(surface, COLORS["card"], detail_rect, border_radius=15)
        
        # 绘制公式名称
        name_surface = heading_font.render(formula_data["name"], True, COLORS["primary"])
        surface.blit(name_surface, (350, 120))
        
        # 绘制公式符号
        formula_text = formula_data["symbol"]
        formula_surface = formula_font.render(formula_text, True, COLORS["accent"])
        formula_rect = formula_surface.get_rect(center=(WIDTH//2, 200))
        surface.blit(formula_surface, formula_rect)
        
        y_offset = 250
        
        # 绘制描述
        if "description" in formula_data:
            desc_surface = body_font.render("📖 描述: " + formula_data["description"], True, COLORS["text"])
            surface.blit(desc_surface, (350, y_offset))
            y_offset += 40
        
        # 绘制变量说明
        if "variables" in formula_data:
            var_surface = body_font.render("📊 变量说明:", True, COLORS["text"])
            surface.blit(var_surface, (350, y_offset))
            y_offset += 30
            
            for var in formula_data["variables"]:
                var_text = f"  {var['symbol']}: {var['name']}"
                var_render = small_font.render(var_text, True, COLORS["text"])
                surface.blit(var_render, (370, y_offset))
                y_offset += 25
        
        # 绘制示例
        if "example" in formula_data:
            example_surface = body_font.render("🔢 示例:", True, COLORS["text"])
            surface.blit(example_surface, (350, y_offset))
            y_offset += 30
            
            example_text = "  " + formula_data["example"]
            example_render = small_font.render(example_text, True, COLORS["text"])
            surface.blit(example_render, (370, y_offset))
            y_offset += 40
    
    def draw_formula_list(self, surface, category_key):
        """绘制公式列表"""
        category = MATHEMATICS_FORMULAS[category_key]
        formulas = category["formulas"]
        
        # 绘制分类标题
        title = heading_font.render(f"{category['name']} - 公式列表", True, COLORS["text"])
        surface.blit(title, (350, 100))
        
        # 绘制分类描述
        desc = body_font.render(f"包含 {len(formulas)} 个重要公式", True, COLORS["text_light"])
        surface.blit(desc, (350, 140))
        
        # 创建公式卡片
        self.formula_cards = []
        card_width = 800
        card_height = 120
        margin = 15
        
        for i, formula in enumerate(formulas):
            y = 180 + i * (card_height + margin)
            card = FormulaCard(350, y, card_width, card_height, formula, i+1)
            self.formula_cards.append(card)
            card.draw(surface)
    
    def draw_search_results(self, surface, results):
        """绘制搜索结果"""
        if not results:
            # 没有结果
            no_result = heading_font.render("未找到相关公式", True, COLORS["text_light"])
            surface.blit(no_result, (WIDTH//2 - 100, HEIGHT//2))
            return
            
        title = heading_font.render(f"搜索结果 ({len(results)} 个)", True, COLORS["text"])
        surface.blit(title, (350, 100))
        
        # 绘制结果卡片
        self.formula_cards = []
        card_width = 800
        card_height = 120
        margin = 15
        
        for i, (category_key, formula_idx) in enumerate(results):
            formula = MATHEMATICS_FORMULAS[category_key]["formulas"][formula_idx]
            y = 150 + i * (card_height + margin)
            card = FormulaCard(350, y, card_width, card_height, formula, i+1)
            self.formula_cards.append(card)
            card.draw(surface)
    
    def search_formulas(self, keyword):
        """搜索公式"""
        if not keyword:
            return []
            
        results = []
        keyword = keyword.lower()
        
        for cat_key, category in MATHEMATICS_FORMULAS.items():
            for i, formula in enumerate(category["formulas"]):
                # 在名称、描述、符号中搜索
                search_text = (formula["name"] + formula["description"] + 
                             formula["symbol"]).lower()
                
                if keyword in search_text:
                    results.append((cat_key, i))
        
        return results
    
    def random_formula(self):
        """随机选择一个公式"""
        import random
        cat_key = random.choice(list(MATHEMATICS_FORMULAS.keys()))
        formula_idx = random.randrange(len(MATHEMATICS_FORMULAS[cat_key]["formulas"]))
        self.selected_formula = MATHEMATICS_FORMULAS[cat_key]["formulas"][formula_idx]
        return True
    
    def reset_search(self):
        """重置搜索"""
        self.search_box.text = ""
        self.search_results = []
        self.search_mode = False
        return True
    
    def run(self):
        """运行主循环"""
        clock = pygame.time.Clock()
        running = True
        
        while running:
            dt = clock.tick(60)  # 限制60FPS
            
            mouse_pos = pygame.mouse.get_pos()
            
            # 处理事件
            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    running = False
                    
                elif event.type == pygame.KEYDOWN:
                    if event.key == pygame.K_ESCAPE:
                        if self.selected_formula:
                            self.selected_formula = None
                        elif self.search_mode:
                            self.reset_search()
                        else:
                            self.current_category = "algebra"
                    
                    # 处理搜索框输入
                    result = self.search_box.handle_event(event)
                    if result is not None:
                        self.search_results = self.search_formulas(result)
                        self.search_mode = bool(self.search_results)
                
                elif event.type == pygame.MOUSEBUTTONDOWN:
                    # 处理搜索框点击
                    self.search_box.handle_event(event)
                    
                    # 处理返回按钮
                    if self.selected_formula and self.back_button.handle_click(mouse_pos):
                        self.selected_formula = None
                    
                    # 处理控制按钮
                    for button in self.control_buttons:
                        button.handle_click(mouse_pos)
                    
                    # 处理分类卡片点击
                    if not self.selected_formula and not self.search_mode:
                        for card in self.category_cards:
                            if card.check_hover(mouse_pos):
                                self.current_category = card.category_key
                                for c in self.category_cards:
                                    c.active = (c == card)
                    
                    # 处理公式卡片点击
                    for card in self.formula_cards:
                        if card.check_hover(mouse_pos):
                            self.selected_formula = card.formula_data
                            break
            
            # 更新搜索框光标
            if self.search_box.active:
                self.search_box.update(dt)
            
            # 绘制界面
            screen.fill(COLORS["bg"])
            
            # 绘制侧边栏
            self.draw_sidebar(screen)
            
            if self.selected_formula:
                # 绘制公式详情页
                self.draw_formula_detail(screen, self.selected_formula)
                self.back_button.draw(screen)
                self.back_button.check_hover(mouse_pos)
                
            elif self.search_mode:
                # 绘制搜索结果
                self.draw_search_results(screen, self.search_results)
                
            else:
                # 绘制主界面
                # 绘制搜索框
                self.search_box.draw(screen)
                self.search_box.check_hover(mouse_pos)  # 现在这个方法已定义
                
                # 绘制分类卡片
                for card in self.category_cards:
                    card.draw(screen)
                    card.check_hover(mouse_pos)
                    if card.category_key == self.current_category:
                        card.active = True
                    else:
                        card.active = False
                
                # 绘制公式列表
                self.draw_formula_list(screen, self.current_category)
            
            # 绘制控制按钮
            for button in self.control_buttons:
                button.draw(screen)
                button.check_hover(mouse_pos)
            
            # 绘制底部状态栏
            pygame.draw.rect(screen, COLORS["primary"], (0, HEIGHT-30, WIDTH, 30))
            status_text = f"数学公式查询系统 | 当前分类: {MATHEMATICS_FORMULAS[self.current_category]['name']} | 按ESC返回"
            status_surface = small_font.render(status_text, True, COLORS["white"])
            screen.blit(status_surface, (20, HEIGHT-25))
            
            pygame.display.flip()
        
        pygame.quit()
        sys.exit()

def main():
    """主函数"""
    app = MathFormulaApp()
    app.run()

if __name__ == "__main__":
    main()