import pygame
import sys
import math
import random
from datetime import datetime, timedelta
import numpy as np

# 初始化 Pygame
pygame.init()

# 颜色定义
COLORS = {
    'background': (245, 245, 250),      # 浅色背景
    'panel': (255, 255, 255),           # 面板背景
    'grid': (230, 230, 235),            # 网格线
    'axis': (60, 60, 80),               # 坐标轴
    'text': (40, 40, 60),               # 文字
    'subject_colors': {
        '数学': (70, 130, 180),         # 蓝色
        '语文': (220, 100, 100),        # 红色
        '英语': (100, 180, 100),        # 绿色
        '物理': (180, 120, 220),        # 紫色
        '化学': (220, 180, 80),         # 橙色
        '生物': (80, 180, 220),         # 青色
        '历史': (220, 140, 100),        # 橙色红
        '地理': (140, 200, 140),        # 浅绿
    },
    'button_normal': (80, 100, 160),    # 普通按钮
    'button_hover': (100, 130, 190),    # 按钮悬停
    'button_press': (120, 150, 210),    # 按钮按下
    'highlight': (255, 220, 100),       # 高亮色
    'prediction': (180, 180, 180, 150), # 预测区域
    'average_line': (150, 150, 150),    # 平均线
    'trend_line': (220, 100, 100),      # 趋势线
    'goal_line': (100, 180, 100),       # 目标线
}

# 窗口设置
WIDTH, HEIGHT = 1200, 800
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("学生成绩走势图分析系统")
clock = pygame.time.Clock()

# ==================== 修复中文显示问题 ====================
# 尝试加载中文字体，如果失败则使用系统字体
def load_font(size):
    """加载字体，优先使用中文字体"""
    try:
        # 尝试加载常见的中文字体
        font_paths = [
            "C:/Windows/Fonts/msyh.ttc",  # 微软雅黑
            "C:/Windows/Fonts/simhei.ttf", # 黑体
            "C:/Windows/Fonts/simsun.ttc", # 宋体
            "/System/Library/Fonts/PingFang.ttc",  # macOS 苹方
            "/usr/share/fonts/truetype/wqy/wqy-microhei.ttc",  # Linux 文泉驿
        ]
        
        for font_path in font_paths:
            try:
                return pygame.font.Font(font_path, size)
            except:
                continue
        
        # 如果都失败，使用系统字体
        return pygame.font.SysFont('simhei', size)  # 使用黑体
    except:
        # 最终备用方案
        return pygame.font.Font(None, size)

# 加载不同大小的字体
title_font = load_font(48)
header_font = load_font(36)
text_font = load_font(28)
small_font = load_font(24)
large_font = load_font(60)

# ==================== 辅助函数：渲染中文文本 ====================
def render_text(text, font, color, antialias=True):
    """渲染文本，处理可能的编码问题"""
    try:
        return font.render(text, antialias, color)
    except:
        # 如果渲染失败，尝试使用UTF-8编码
        try:
            if isinstance(text, str):
                text = text.encode('utf-8', 'ignore').decode('utf-8')
            return font.render(text, antialias, color)
        except:
            # 最终备用：显示错误信息
            return font.render("渲染错误", antialias, color)

# 学生成绩数据类
class Student:
    def __init__(self, name, student_id):
        self.name = name
        self.student_id = student_id
        self.scores = {}  # 科目: [成绩列表]
        self.exam_dates = []  # 考试日期列表
        self.goals = {}  # 科目: 目标分数
        self.notes = {}  # 日期+科目: 备注
    
    def add_score(self, subject, score, date, note=""):
        if subject not in self.scores:
            self.scores[subject] = []
        
        # 找到日期索引
        if date not in self.exam_dates:
            self.exam_dates.append(date)
            self.exam_dates.sort()
        
        date_index = self.exam_dates.index(date)
        
        # 确保列表足够长
        while len(self.scores[subject]) <= date_index:
            self.scores[subject].append(None)
        
        self.scores[subject][date_index] = score
        
        if note:
            key = f"{date}_{subject}"
            self.notes[key] = note
    
    def get_score(self, subject, date_index):
        if subject in self.scores and date_index < len(self.scores[subject]):
            return self.scores[subject][date_index]
        return None
    
    def get_all_scores(self, subject):
        return self.scores.get(subject, [])
    
    def get_subjects(self):
        return list(self.scores.keys())
    
    def calculate_average(self, subject):
        scores = [s for s in self.get_all_scores(subject) if s is not None]
        if scores:
            return sum(scores) / len(scores)
        return 0
    
    def calculate_trend(self, subject):
        """计算成绩趋势（线性回归斜率）"""
        scores = self.get_all_scores(subject)
        valid_scores = [(i, s) for i, s in enumerate(scores) if s is not None]
        
        if len(valid_scores) < 2:
            return 0
        
        x = [v[0] for v in valid_scores]
        y = [v[1] for v in valid_scores]
        
        # 线性回归
        n = len(x)
        sum_x = sum(x)
        sum_y = sum(y)
        sum_xy = sum(x[i] * y[i] for i in range(n))
        sum_x2 = sum(x_i * x_i for x_i in x)
        
        slope = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x)
        return slope
    
    def predict_next_score(self, subject):
        """预测下一次考试成绩"""
        scores = [s for s in self.get_all_scores(subject) if s is not None]
        if len(scores) < 2:
            return None
        
        # 简单线性预测
        x = list(range(len(scores)))
        slope = self.calculate_trend(subject)
        
        if slope == 0:
            return sum(scores) / len(scores)
        
        next_x = len(scores)
        next_y = scores[-1] + slope
        
        # 限制在0-100分之间
        return max(0, min(100, next_y))
    
    def get_strengths_weaknesses(self):
        """分析优势科目和薄弱科目"""
        subjects = self.get_subjects()
        if not subjects:
            return [], []
        
        averages = {s: self.calculate_average(s) for s in subjects}
        sorted_subjects = sorted(averages.items(), key=lambda x: x[1], reverse=True)
        
        # 取前3名为优势科目，后3名为薄弱科目
        strengths = sorted_subjects[:3]
        weaknesses = sorted_subjects[-3:]
        
        return strengths, weaknesses

# 按钮类
class Button:
    def __init__(self, x, y, width, height, text, color=COLORS['button_normal'], 
                 hover_color=COLORS['button_hover'], text_color=(255, 255, 255)):
        self.rect = pygame.Rect(x, y, width, height)
        self.text = text
        self.color = color
        self.hover_color = hover_color
        self.text_color = text_color
        self.is_hovered = False
        self.is_pressed = False
        self.radius = 8
    
    def draw(self, surface):
        # 绘制阴影
        shadow_rect = self.rect.copy()
        shadow_rect.x += 3
        shadow_rect.y += 3
        pygame.draw.rect(surface, (200, 200, 200), shadow_rect, border_radius=self.radius)
        
        # 绘制按钮
        current_color = self.color
        if self.is_pressed:
            current_color = COLORS['button_press']
        elif self.is_hovered:
            current_color = self.hover_color
        
        pygame.draw.rect(surface, current_color, self.rect, border_radius=self.radius)
        
        # 绘制边框
        pygame.draw.rect(surface, (255, 255, 255), self.rect, 2, border_radius=self.radius)
        
        # 绘制文字（使用修复的渲染函数）
        text_surf = render_text(self.text, small_font, self.text_color)
        text_rect = text_surf.get_rect(center=self.rect.center)
        surface.blit(text_surf, text_rect)
    
    def check_hover(self, pos):
        self.is_hovered = self.rect.collidepoint(pos)
        return self.is_hovered
    
    def handle_event(self, event):
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            if self.is_hovered:
                self.is_pressed = True
                return True
        elif event.type == pygame.MOUSEBUTTONUP and event.button == 1:
            self.is_pressed = False
        return False

# 图表类
class ScoreChart:
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
        self.padding = 60
        self.selected_point = None
        self.show_predictions = True
        self.show_average = True
        self.show_trend = True
        self.show_goals = True
    
    def draw_grid(self, surface, num_exams):
        """绘制网格"""
        grid_rect = pygame.Rect(self.x + self.padding, self.y + 20, 
                               self.width - self.padding - 20, self.height - 40)
        
        # 网格背景
        pygame.draw.rect(surface, COLORS['panel'], grid_rect)
        
        # 水平网格线（分数）
        for i in range(0, 101, 10):
            y = grid_rect.bottom - (i / 100) * (grid_rect.height - 40)
            if i % 20 == 0:
                # 主要网格线
                pygame.draw.line(surface, COLORS['grid'], 
                               (grid_rect.left, y), (grid_rect.right, y), 2)
                
                # 分数标签（使用修复的渲染函数）
                score_text = render_text(str(i), small_font, COLORS['text'])
                surface.blit(score_text, (grid_rect.left - 35, y - 10))
            else:
                # 次要网格线
                pygame.draw.line(surface, (240, 240, 245), 
                               (grid_rect.left, y), (grid_rect.right, y), 1)
        
        # 垂直网格线（考试次数）
        if num_exams > 1:
            for i in range(num_exams):
                x = grid_rect.left + (i / (num_exams - 1)) * (grid_rect.width - 40)
                if i % 2 == 0:
                    pygame.draw.line(surface, COLORS['grid'], 
                                   (x, grid_rect.top), (x, grid_rect.bottom), 2)
                else:
                    pygame.draw.line(surface, (240, 240, 245), 
                                   (x, grid_rect.top), (x, grid_rect.bottom), 1)
        
        # 坐标轴
        pygame.draw.line(surface, COLORS['axis'], 
                        (grid_rect.left, grid_rect.top), 
                        (grid_rect.left, grid_rect.bottom), 3)
        pygame.draw.line(surface, COLORS['axis'], 
                        (grid_rect.left, grid_rect.bottom), 
                        (grid_rect.right, grid_rect.bottom), 3)
        
        # 坐标轴标签（使用修复的渲染函数）
        title_text = render_text("考试成绩走势图", text_font, COLORS['text'])
        surface.blit(title_text, (grid_rect.left + grid_rect.width // 2 - title_text.get_width() // 2, 
                                 self.y - 10))
        
        x_label = render_text("考试次数", small_font, COLORS['text'])
        surface.blit(x_label, (grid_rect.left + grid_rect.width // 2 - x_label.get_width() // 2, 
                              grid_rect.bottom + 25))
        
        y_label = render_text("分数", small_font, COLORS['text'])
        surface.blit(y_label, (grid_rect.left - 50, grid_rect.top + grid_rect.height // 2 - 20))
        
        return grid_rect
    
    def draw_scores(self, surface, student, subject, grid_rect):
        """绘制成绩曲线"""
        if subject not in student.scores:
            return
        
        scores = student.get_all_scores(subject)
        valid_points = [(i, score) for i, score in enumerate(scores) if score is not None]
        
        if len(valid_points) < 2:
            return
        
        color = COLORS['subject_colors'].get(subject, (100, 100, 100))
        
        # 绘制连线
        points = []
        for i, score in valid_points:
            x = grid_rect.left + 20 + (i / (len(scores) - 1)) * (grid_rect.width - 40)
            y = grid_rect.bottom - 20 - (score / 100) * (grid_rect.height - 40)
            points.append((x, y))
        
        # 绘制平滑曲线
        if len(points) >= 2:
            for i in range(len(points) - 1):
                pygame.draw.line(surface, color, points[i], points[i + 1], 3)
        
        # 绘制数据点
        for i, (x, y) in enumerate(points):
            pygame.draw.circle(surface, color, (int(x), int(y)), 8)
            pygame.draw.circle(surface, (255, 255, 255), (int(x), int(y)), 4)
            
            # 显示分数标签
            score = valid_points[i][1]
            score_text = render_text(f"{score:.1f}", small_font, color)
            surface.blit(score_text, (x - 15, y - 25))
            
            # 检查鼠标悬停
            mouse_pos = pygame.mouse.get_pos()
            distance = math.sqrt((mouse_pos[0] - x) ** 2 + (mouse_pos[1] - y) ** 2)
            if distance < 10:
                self.selected_point = (i, score, subject)
                
                # 显示详细信息
                info_rect = pygame.Rect(x - 100, y - 80, 200, 60)
                pygame.draw.rect(surface, (255, 255, 255), info_rect, border_radius=5)
                pygame.draw.rect(surface, color, info_rect, 2, border_radius=5)
                
                exam_num = i + 1
                info_text = render_text(f"第{exam_num}次考试: {score:.1f}分", small_font, COLORS['text'])
                surface.blit(info_text, (info_rect.centerx - info_text.get_width() // 2, 
                                       info_rect.top + 10))
                
                if student.exam_dates and i < len(student.exam_dates):
                    date_text = render_text(f"日期: {student.exam_dates[i]}", small_font, COLORS['text'])
                    surface.blit(date_text, (info_rect.centerx - date_text.get_width() // 2, 
                                           info_rect.top + 30))
    
    def draw_average_line(self, surface, student, subject, grid_rect):
        """绘制平均分线"""
        if not self.show_average:
            return
        
        avg = student.calculate_average(subject)
        if avg == 0:
            return
        
        y = grid_rect.bottom - 20 - (avg / 100) * (grid_rect.height - 40)
        
        # 绘制虚线
        dash_length = 10
        gap_length = 5
        x_start = grid_rect.left + 20
        x_end = grid_rect.right - 20
        
        x = x_start
        while x < x_end:
            end_x = min(x + dash_length, x_end)
            pygame.draw.line(surface, COLORS['average_line'], (x, y), (end_x, y), 2)
            x += dash_length + gap_length
        
        # 平均分标签
        avg_text = render_text(f"平均: {avg:.1f}", small_font, COLORS['average_line'])
        surface.blit(avg_text, (grid_rect.right - 60, y - 20))
    
    def draw_trend_line(self, surface, student, subject, grid_rect):
        """绘制趋势线"""
        if not self.show_trend:
            return
        
        scores = [s for s in student.get_all_scores(subject) if s is not None]
        if len(scores) < 2:
            return
        
        # 计算线性回归
        x_indices = list(range(len(scores)))
        slope = student.calculate_trend(subject)
        
        if slope == 0:
            return
        
        # 计算起点和终点
        start_x = grid_rect.left + 20
        end_x = grid_rect.right - 20
        start_y = grid_rect.bottom - 20 - (scores[0] / 100) * (grid_rect.height - 40)
        end_y = start_y - slope * (grid_rect.width - 40) / (len(scores) - 1)
        
        # 绘制趋势线
        pygame.draw.line(surface, COLORS['trend_line'], (start_x, start_y), (end_x, end_y), 2)
        
        # 趋势箭头
        arrow_size = 10
        angle = math.atan2(end_y - start_y, end_x - start_x)
        
        # 箭头点
        arrow_x1 = end_x - arrow_size * math.cos(angle - math.pi/6)
        arrow_y1 = end_y - arrow_size * math.sin(angle - math.pi/6)
        arrow_x2 = end_x - arrow_size * math.cos(angle + math.pi/6)
        arrow_y2 = end_y - arrow_size * math.sin(angle + math.pi/6)
        
        pygame.draw.polygon(surface, COLORS['trend_line'], 
                          [(end_x, end_y), (arrow_x1, arrow_y1), (arrow_x2, arrow_y2)])
        
        # 趋势标签
        trend_text = "上升" if slope > 0 else "下降" if slope < 0 else "平稳"
        trend_color = (100, 180, 100) if slope > 0 else (220, 100, 100) if slope < 0 else (150, 150, 150)
        
        trend_label = render_text(f"趋势: {trend_text} ({slope:.2f}/次)", small_font, trend_color)
        surface.blit(trend_label, (grid_rect.right - 150, grid_rect.top + 10))
    
    def draw_prediction(self, surface, student, subject, grid_rect):
        """绘制预测区域"""
        if not self.show_predictions:
            return
        
        scores = [s for s in student.get_all_scores(subject) if s is not None]
        if len(scores) < 2:
            return
        
        # 预测下一次成绩
        next_score = student.predict_next_score(subject)
        if next_score is None:
            return
        
        # 预测区域（置信区间）
        last_index = len(scores) - 1
        last_x = grid_rect.left + 20 + (last_index / (len(scores) - 1)) * (grid_rect.width - 40)
        next_x = grid_rect.right - 20
        
        last_y = grid_rect.bottom - 20 - (scores[-1] / 100) * (grid_rect.height - 40)
        next_y = grid_rect.bottom - 20 - (next_score / 100) * (grid_rect.height - 40)
        
        # 绘制预测区域（渐变）
        prediction_surface = pygame.Surface((self.width, self.height), pygame.SRCALPHA)
        
        # 创建预测多边形
        points = [
            (last_x, last_y - 5),
            (last_x, last_y + 5),
            (next_x, next_y + 10),
            (next_x, next_y - 10)
        ]
        
        pygame.draw.polygon(prediction_surface, COLORS['prediction'], points)
        surface.blit(prediction_surface, (0, 0))
        
        # 预测线
        pygame.draw.line(surface, (150, 150, 150, 200), (last_x, last_y), (next_x, next_y), 2)
        
        # 预测点
        pygame.draw.circle(surface, (100, 100, 100), (int(next_x), int(next_y)), 6)
        
        # 预测标签
        predict_text = render_text(f"预测: {next_score:.1f}分", small_font, (100, 100, 100))
        surface.blit(predict_text, (next_x - 40, next_y - 25))
    
    def draw_goal_line(self, surface, student, subject, grid_rect):
        """绘制目标线"""
        if not self.show_goals:
            return
        
        if subject not in student.goals:
            return
        
        goal = student.goals[subject]
        y = grid_rect.bottom - 20 - (goal / 100) * (grid_rect.height - 40)
        
        # 绘制目标线
        pygame.draw.line(surface, COLORS['goal_line'], 
                        (grid_rect.left + 20, y), (grid_rect.right - 20, y), 2)
        
        # 目标标签
        goal_text = render_text(f"目标: {goal}分", small_font, COLORS['goal_line'])
        surface.blit(goal_text, (grid_rect.right - 60, y + 5))
    
    def draw(self, surface, student, subject):
        """绘制完整图表"""
        # 绘制网格
        num_exams = len(student.exam_dates) if student.exam_dates else 1
        grid_rect = self.draw_grid(surface, num_exams)
        
        # 绘制各种线条
        self.draw_average_line(surface, student, subject, grid_rect)
        self.draw_trend_line(surface, student, subject, grid_rect)
        self.draw_goal_line(surface, student, subject, grid_rect)
        self.draw_prediction(surface, student, subject, grid_rect)
        
        # 绘制成绩曲线
        self.draw_scores(surface, student, subject, grid_rect)
        
        return grid_rect

# 统计面板类
class StatisticsPanel:
    def __init__(self, x, y, width, height):
        self.x = x
        self.y = y
        self.width = width
        self.height = height
    
    def draw(self, surface, student, subject):
        """绘制统计信息"""
        panel_rect = pygame.Rect(self.x, self.y, self.width, self.height)
        
        # 面板背景
        pygame.draw.rect(surface, COLORS['panel'], panel_rect, border_radius=10)
        pygame.draw.rect(surface, (200, 200, 210), panel_rect, 2, border_radius=10)
        
        # 标题
        title = render_text(f"{subject} - 统计分析", header_font, COLORS['text'])
        surface.blit(title, (panel_rect.centerx - title.get_width() // 2, panel_rect.y + 20))
        
        if subject not in student.scores:
            no_data = render_text("暂无数据", text_font, (150, 150, 150))
            surface.blit(no_data, (panel_rect.centerx - no_data.get_width() // 2, 
                                 panel_rect.centery))
            return
        
        scores = [s for s in student.get_all_scores(subject) if s is not None]
        if not scores:
            no_data = render_text("暂无有效成绩", text_font, (150, 150, 150))
            surface.blit(no_data, (panel_rect.centerx - no_data.get_width() // 2, 
                                 panel_rect.centery))
            return
        
        # 计算统计指标
        avg = sum(scores) / len(scores)
        max_score = max(scores)
        min_score = min(scores)
        latest = scores[-1] if scores else 0
        trend = student.calculate_trend(subject)
        
        # 标准差
        if len(scores) > 1:
            variance = sum((x - avg) ** 2 for x in scores) / len(scores)
            std_dev = math.sqrt(variance)
        else:
            std_dev = 0
        
        # 稳定性评级
        if std_dev < 5:
            stability = "非常稳定"
            stability_color = (100, 180, 100)
        elif std_dev < 10:
            stability = "比较稳定"
            stability_color = (180, 180, 100)
        elif std_dev < 15:
            stability = "波动较大"
            stability_color = (220, 150, 100)
        else:
            stability = "很不稳定"
            stability_color = (220, 100, 100)
        
        # 绘制统计信息
        y_offset = 70
        line_height = 40
        
        stats = [
            ("考试次数", f"{len(scores)} 次"),
            ("平均分", f"{avg:.1f} 分"),
            ("最高分", f"{max_score:.1f} 分"),
            ("最低分", f"{min_score:.1f} 分"),
            ("最近一次", f"{latest:.1f} 分"),
            ("标准差", f"{std_dev:.2f}"),
            ("稳定性", stability),
            ("趋势", f"{'↑' if trend > 0 else '↓' if trend < 0 else '→'} {abs(trend):.2f}/次"),
        ]
        
        for i, (label, value) in enumerate(stats):
            y_pos = panel_rect.y + y_offset + i * line_height
            
            # 绘制标签
            label_text = render_text(label + ":", text_font, COLORS['text'])
            surface.blit(label_text, (panel_rect.x + 30, y_pos))
            
            # 绘制值
            if label == "稳定性":
                value_color = stability_color
            elif label == "趋势":
                value_color = (100, 180, 100) if trend > 0 else (220, 100, 100) if trend < 0 else (150, 150, 150)
            else:
                value_color = COLORS['subject_colors'].get(subject, (100, 100, 100))
            
            value_text = render_text(value, text_font, value_color)
            surface.blit(value_text, (panel_rect.right - 30 - value_text.get_width(), y_pos))
        
        # 绘制进度条（目标达成度）
        if subject in student.goals:
            goal = student.goals[subject]
            progress = min(100, (latest / goal) * 100) if goal > 0 else 0
            
            # 进度条背景
            progress_y = panel_rect.bottom - 60
            progress_bg = pygame.Rect(panel_rect.x + 30, progress_y, panel_rect.width - 60, 20)
            pygame.draw.rect(surface, (230, 230, 230), progress_bg, border_radius=10)
            
            # 进度条前景
            progress_width = (progress_bg.width * progress / 100)
            progress_fg = pygame.Rect(progress_bg.left, progress_bg.top, progress_width, progress_bg.height)
            progress_color = (100, 180, 100) if progress >= 100 else (220, 180, 100)
            pygame.draw.rect(surface, progress_color, progress_fg, border_radius=10)
            
            # 进度文本
            progress_text = render_text(f"目标达成度: {progress:.1f}%", small_font, COLORS['text'])
            surface.blit(progress_text, (panel_rect.centerx - progress_text.get_width() // 2, 
                                       progress_y + 25))

# 生成示例数据
def generate_sample_data():
    """生成示例学生数据"""
    student = Student("张三", "2023001")
    
    # 生成考试日期（最近6个月）
    base_date = datetime.now()
    exam_dates = []
    for i in range(6):
        date = base_date - timedelta(days=30 * (5 - i))
        exam_dates.append(date.strftime("%Y-%m-%d"))
    
    student.exam_dates = exam_dates
    
    # 生成各科成绩（有一定趋势和波动）
    subjects = ["数学", "语文", "英语", "物理", "化学"]
    
    for subject in subjects:
        # 基础分数
        if subject == "数学":
            base = 75
            trend = 1.5  # 上升趋势
        elif subject == "语文":
            base = 80
            trend = 0.5  # 缓慢上升
        elif subject == "英语":
            base = 85
            trend = -0.5  # 缓慢下降
        elif subject == "物理":
            base = 70
            trend = 2.0  # 明显上升
        elif subject == "化学":
            base = 65
            trend = 1.0  # 上升
        
        # 生成6次考试成绩
        for i in range(6):
            # 基础分数 + 趋势 + 随机波动
            score = base + trend * i + random.uniform(-5, 5)
            score = max(0, min(100, score))  # 限制在0-100之间
            
            student.add_score(subject, round(score, 1), exam_dates[i])
        
        # 设置目标分数
        if subject == "数学":
            student.goals[subject] = 90
        elif subject == "语文":
            student.goals[subject] = 85
        elif subject == "英语":
            student.goals[subject] = 90
        elif subject == "物理":
            student.goals[subject] = 80
        elif subject == "化学":
            student.goals[subject] = 75
    
    return student

# ==================== 创建界面元素 ====================
student = generate_sample_data()
chart = ScoreChart(400, 100, 750, 500)
stats_panel = StatisticsPanel(20, 100, 350, 350)
subject_panel = StatisticsPanel(20, 470, 350, 300)

# 创建按钮
buttons = []
subject_buttons = []

# 科目选择按钮
subject_x = 20
subject_y = 50
subject_width = 70
subject_height = 40
subject_spacing = 10

subjects = student.get_subjects()
for i, subject in enumerate(subjects):
    x = subject_x + i * (subject_width + subject_spacing)
    color = COLORS['subject_colors'].get(subject, COLORS['button_normal'])
    hover_color = tuple(min(255, c + 30) for c in color)
    
    button = Button(x, subject_y, subject_width, subject_height, subject, color, hover_color)
    subject_buttons.append(button)

# 控制按钮
control_buttons_y = 620
control_buttons = [
    Button(400, control_buttons_y, 120, 40, "显示预测", 
           (100, 150, 100) if chart.show_predictions else COLORS['button_normal'],
           (120, 180, 120)),
    Button(530, control_buttons_y, 120, 40, "显示平均线",
           (100, 150, 100) if chart.show_average else COLORS['button_normal'],
           (120, 180, 120)),
    Button(660, control_buttons_y, 120, 40, "显示趋势线",
           (100, 150, 100) if chart.show_trend else COLORS['button_normal'],
           (120, 180, 120)),
    Button(790, control_buttons_y, 120, 40, "显示目标线",
           (100, 150, 100) if chart.show_goals else COLORS['button_normal'],
           (120, 180, 120)),
    Button(920, control_buttons_y, 120, 40, "添加成绩",
           COLORS['button_normal'], COLORS['button_hover']),
    Button(1050, control_buttons_y, 120, 40, "导出报告",
           COLORS['button_normal'], COLORS['button_hover']),
]

# 当前选中的科目
current_subject = subjects[0] if subjects else ""

# ==================== 主循环 ====================
running = True
while running:
    mouse_pos = pygame.mouse.get_pos()
    
    # 事件处理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        
        # 更新按钮悬停状态
        for button in subject_buttons + control_buttons:
            button.check_hover(mouse_pos)
        
        # 处理科目按钮点击
        if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
            for button in subject_buttons:
                if button.handle_event(event):
                    current_subject = button.text
            
            # 处理控制按钮点击
            for i, button in enumerate(control_buttons):
                if button.handle_event(event):
                    if i == 0:  # 显示预测
                        chart.show_predictions = not chart.show_predictions
                        control_buttons[0].color = (100, 150, 100) if chart.show_predictions else COLORS['button_normal']
                    elif i == 1:  # 显示平均线
                        chart.show_average = not chart.show_average
                        control_buttons[1].color = (100, 150, 100) if chart.show_average else COLORS['button_normal']
                    elif i == 2:  # 显示趋势线
                        chart.show_trend = not chart.show_trend
                        control_buttons[2].color = (100, 150, 100) if chart.show_trend else COLORS['button_normal']
                    elif i == 3:  # 显示目标线
                        chart.show_goals = not chart.show_goals
                        control_buttons[3].color = (100, 150, 100) if chart.show_goals else COLORS['button_normal']
                    elif i == 4:  # 添加成绩
                        # 这里可以添加添加成绩的功能
                        print("添加成绩功能")
                    elif i == 5:  # 导出报告
                        # 这里可以添加导出报告的功能
                        print("导出报告功能")
    
    # 绘制背景
    screen.fill(COLORS['background'])
    
    # 绘制标题（使用修复的渲染函数）
    title = render_text(f"学生成绩走势图分析系统 - {student.name}", title_font, COLORS['text'])
    screen.blit(title, (WIDTH // 2 - title.get_width() // 2, 10))
    
    # 绘制学生信息
    info_text = render_text(f"学号: {student.student_id} | 科目数: {len(subjects)} | 考试次数: {len(student.exam_dates)}", 
                           text_font, (100, 100, 120))
    screen.blit(info_text, (WIDTH // 2 - info_text.get_width() // 2, 55))
    
    # 绘制科目选择按钮
    for button in subject_buttons:
        button.draw(screen)
        # 高亮当前选中的科目
        if button.text == current_subject:
            pygame.draw.rect(screen, COLORS['highlight'], button.rect, 3, border_radius=8)
    
    # 绘制图表
    chart.draw(screen, student, current_subject)
    
    # 绘制统计面板
    stats_panel.draw(screen, student, current_subject)
    
    # 绘制科目对比面板
    subject_panel_rect = pygame.Rect(20, 470, 350, 300)
    pygame.draw.rect(screen, COLORS['panel'], subject_panel_rect, border_radius=10)
    pygame.draw.rect(screen, (200, 200, 210), subject_panel_rect, 2, border_radius=10)
    
    # 科目对比标题
    compare_title = render_text("科目对比", header_font, COLORS['text'])
    screen.blit(compare_title, (subject_panel_rect.centerx - compare_title.get_width() // 2, 
                              subject_panel_rect.y + 20))
    
    # 计算各科平均分
    subject_avgs = []
    for subject in subjects:
        avg = student.calculate_average(subject)
        subject_avgs.append((subject, avg))
    
    # 按平均分排序
    subject_avgs.sort(key=lambda x: x[1], reverse=True)
    
    # 绘制科目排名
    y_offset = 70
    for i, (subject, avg) in enumerate(subject_avgs):
        y_pos = subject_panel_rect.y + y_offset + i * 40
        
        # 排名序号
        rank_text = render_text(f"{i+1}.", text_font, COLORS['text'])
        screen.blit(rank_text, (subject_panel_rect.x + 20, y_pos))
        
        # 科目名称
        subject_color = COLORS['subject_colors'].get(subject, (100, 100, 100))
        subject_text = render_text(subject, text_font, subject_color)
        screen.blit(subject_text, (subject_panel_rect.x + 60, y_pos))
        
        # 平均分
        avg_text = render_text(f"{avg:.1f}分", text_font, COLORS['text'])
        screen.blit(avg_text, (subject_panel_rect.right - 30 - avg_text.get_width(), y_pos))
        
        # 进度条
        bar_width = 150
        bar_height = 8
        bar_x = subject_panel_rect.x + 130
        bar_y = y_pos + 15
        
        # 进度条背景
        bar_bg = pygame.Rect(bar_x, bar_y, bar_width, bar_height)
        pygame.draw.rect(screen, (230, 230, 230), bar_bg, border_radius=4)
        
        # 进度条前景
        progress = avg / 100
        bar_fg = pygame.Rect(bar_x, bar_y, bar_width * progress, bar_height)
        pygame.draw.rect(screen, subject_color, bar_fg, border_radius=4)
    
    # 绘制控制按钮
    for button in control_buttons:
        button.draw(screen)
    
    # 绘制底部信息
    bottom_text = render_text("点击科目按钮切换科目 | 点击控制按钮切换显示选项", small_font, (150, 150, 150))
    screen.blit(bottom_text, (WIDTH // 2 - bottom_text.get_width() // 2, HEIGHT - 30))
    
    # 更新显示
    pygame.display.flip()
    clock.tick(60)

# 退出 Pygame
pygame.quit()
sys.exit()