import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import matplotlib.pyplot as plt
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg
from matplotlib.figure import Figure
import numpy as np
from datetime import datetime

class ScoreAnalysisTool:
    def __init__(self, root):
        self.root = root
        self.root.title("成绩走势图分析器")
        self.root.geometry("1200x700")
        
        self.students = {}
        self.subjects = []
        self.current_student = None
        self.current_subject = None
        
        self.load_sample_data()
        self.create_interface()
        
    def load_sample_data(self):
        sample_data = {
            "张三": {
                "student_id": "2023001",
                "class_name": "高三(1)班",
                "scores": {
                    "语文": [85, 88, 92, 90, 95, 93, 98, 96, 97, 100],
                    "数学": [78, 82, 85, 88, 90, 92, 88, 85, 90, 95],
                    "英语": [92, 90, 88, 85, 87, 90, 92, 94, 96, 98]
                }
            },
            "李四": {
                "student_id": "2023002",
                "class_name": "高三(1)班",
                "scores": {
                    "语文": [90, 88, 85, 87, 90, 92, 94, 96, 98, 100],
                    "数学": [95, 92, 90, 88, 85, 90, 92, 95, 97, 100],
                    "英语": [85, 87, 90, 92, 94, 96, 98, 100, 98, 96]
                }
            }
        }
        
        self.students = sample_data
        self.subjects = list(sample_data["张三"]["scores"].keys())
        self.current_student = "张三"
        self.current_subject = "语文"
        
    def create_interface(self):
        main_frame = ttk.Frame(self.root, padding="10")
        main_frame.pack(fill=tk.BOTH, expand=True)
        
        control_frame = ttk.LabelFrame(main_frame, text="控制面板", padding="10")
        control_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 10))
        
        ttk.Label(control_frame, text="选择学生:").pack(anchor=tk.W, pady=(0, 5))
        self.student_var = tk.StringVar()
        self.student_combo = ttk.Combobox(
            control_frame,
            textvariable=self.student_var,
            state="readonly",
            width=20
        )
        self.student_combo.pack(fill=tk.X, pady=(0, 10))
        self.student_combo.bind("<<ComboboxSelected>>", self.on_student_change)
        
        ttk.Label(control_frame, text="选择科目:").pack(anchor=tk.W, pady=(0, 5))
        self.subject_var = tk.StringVar()
        self.subject_combo = ttk.Combobox(
            control_frame,
            textvariable=self.subject_var,
            state="readonly",
            width=20
        )
        self.subject_combo.pack(fill=tk.X, pady=(0, 10))
        self.subject_combo.bind("<<ComboboxSelected>>", self.on_subject_change)
        
        self.chart_type_var = tk.StringVar(value="折线图")
        chart_frame = ttk.Frame(control_frame)
        chart_frame.pack(fill=tk.X, pady=(0, 10))
        ttk.Radiobutton(chart_frame, text="折线图", variable=self.chart_type_var, 
                       value="折线图", command=self.update_chart).pack(side=tk.LEFT, padx=(0, 10))
        ttk.Radiobutton(chart_frame, text="柱状图", variable=self.chart_type_var, 
                       value="柱状图", command=self.update_chart).pack(side=tk.LEFT)
        
        self.show_trend_line = tk.BooleanVar(value=True)
        self.show_average_line = tk.BooleanVar(value=True)
        self.show_points = tk.BooleanVar(value=True)
        
        ttk.Checkbutton(control_frame, text="显示趋势线", variable=self.show_trend_line, 
                       command=self.update_chart).pack(anchor=tk.W, pady=2)
        ttk.Checkbutton(control_frame, text="显示平均线", variable=self.show_average_line, 
                       command=self.update_chart).pack(anchor=tk.W, pady=2)
        ttk.Checkbutton(control_frame, text="显示数据点", variable=self.show_points, 
                       command=self.update_chart).pack(anchor=tk.W, pady=2)
        
        stats_frame = ttk.LabelFrame(control_frame, text="统计信息", padding="10")
        stats_frame.pack(fill=tk.X, pady=20)
        
        self.stats_text = tk.Text(stats_frame, height=8, width=20, font=("Arial", 10))
        self.stats_text.pack(fill=tk.BOTH, expand=True)
        
        button_frame = ttk.Frame(control_frame)
        button_frame.pack(fill=tk.X, pady=(20, 0))
        
        ttk.Button(button_frame, text="生成图表", command=self.update_chart).pack(
            side=tk.LEFT, fill=tk.X, expand=True, padx=(0, 5))
        ttk.Button(button_frame, text="导出图片", command=self.export_image).pack(
            side=tk.RIGHT, fill=tk.X, expand=True)
        
        chart_container = ttk.LabelFrame(main_frame, text="成绩走势图", padding="10")
        chart_container.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        self.fig = Figure(figsize=(8, 6), dpi=100)
        self.ax = self.fig.add_subplot(111)
        
        self.canvas = FigureCanvasTkAgg(self.fig, chart_container)
        self.canvas.get_tk_widget().pack(fill=tk.BOTH, expand=True)
        
        self.update_lists()
        self.update_chart()
        
    def update_lists(self):
        students = list(self.students.keys())
        self.student_combo["values"] = students
        if students:
            self.student_var.set(self.current_student or students[0])
        
        if self.subjects:
            self.subject_combo["values"] = self.subjects
            if self.subjects:
                self.subject_var.set(self.current_subject or self.subjects[0])
    
    def on_student_change(self, event=None):
        self.current_student = self.student_var.get()
        self.update_chart()
    
    def on_subject_change(self, event=None):
        self.current_subject = self.subject_var.get()
        self.update_chart()
    
    def calculate_statistics(self, scores):
        if not scores:
            return {}
        
        scores_array = np.array(scores)
        return {
            "count": len(scores),
            "max": np.max(scores_array),
            "min": np.min(scores_array),
            "mean": round(np.mean(scores_array), 2),
            "median": np.median(scores_array),
            "std": round(np.std(scores_array), 2),
            "sum": np.sum(scores_array)
        }
    
    def update_chart(self):
        if not self.current_student or not self.current_subject:
            return
        
        scores = self.students[self.current_student]["scores"][self.current_subject]
        exam_numbers = list(range(1, len(scores) + 1))
        
        self.ax.clear()
        
        chart_type = self.chart_type_var.get()
        color = "steelblue"
        
        if chart_type == "折线图":
            self.ax.plot(exam_numbers, scores, 'o-', color=color, linewidth=2, 
                        markersize=8, label='成绩')
            
            if self.show_points.get():
                for i, score in enumerate(scores):
                    self.ax.annotate(f'{score}', (exam_numbers[i], score), 
                                   xytext=(0, 10), textcoords='offset points',
                                   ha='center', fontsize=9)
        else:
            bars = self.ax.bar(exam_numbers, scores, color=color, alpha=0.7, label='成绩')
            
            if self.show_points.get():
                for bar in bars:
                    height = bar.get_height()
                    self.ax.annotate(f'{height:.0f}',
                                   xy=(bar.get_x() + bar.get_width() / 2, height),
                                   xytext=(0, 3), textcoords='offset points',
                                   ha='center', va='bottom', fontsize=9)
        
        if self.show_trend_line.get() and chart_type == "折线图":
            z = np.polyfit(exam_numbers, scores, 1)
            p = np.poly1d(z)
            self.ax.plot(exam_numbers, p(exam_numbers), 'r--', alpha=0.7, 
                        linewidth=2, label='趋势线')
        
        if self.show_average_line.get():
            avg_score = np.mean(scores)
            self.ax.axhline(y=avg_score, color='green', linestyle=':', 
                           linewidth=2, label=f'平均分: {avg_score:.1f}')
        
        student_info = self.students[self.current_student]
        title = f"{self.current_student} - {self.current_subject} 成绩走势图"
        self.ax.set_title(title, fontsize=14, fontweight='bold', pad=20)
        self.ax.set_xlabel('考试次数', fontsize=12)
        self.ax.set_ylabel('分数', fontsize=12)
        
        self.ax.set_xlim(0.5, len(scores) + 0.5)
        score_min = min(scores) - 5
        score_max = max(scores) + 5
        self.ax.set_ylim(max(0, score_min), min(100, score_max))
        
        self.ax.grid(True, alpha=0.3)
        self.ax.legend(loc='upper left', bbox_to_anchor=(0, 1.1))
        self.ax.spines['top'].set_visible(False)
        self.ax.spines['right'].set_visible(False)
        
        self.update_stats(scores)
        self.fig.tight_layout()
        self.canvas.draw()
    
    def update_stats(self, scores):
        stats = self.calculate_statistics(scores)
        
        self.stats_text.delete(1.0, tk.END)
        
        info = f"科目: {self.current_subject}\n"
        info += f"学生: {self.current_student}\n"
        info += f"考试次数: {stats['count']}\n"
        info += "-" * 20 + "\n"
        info += f"最高分: {stats['max']}\n"
        info += f"最低分: {stats['min']}\n"
        info += f"平均分: {stats['mean']}\n"
        info += f"总分: {stats['sum']}\n"
        info += f"标准差: {stats['std']}\n"
        info += f"中位数: {stats['median']}\n"
        info += "-" * 20 + "\n"
        
        if len(scores) > 1:
            trend = "上升" if scores[-1] > scores[0] else "下降"
            change = abs(scores[-1] - scores[0])
            info += f"趋势: {trend} ({change}分)\n"
            
            avg = stats['mean']
            if avg >= 90:
                grade = "优秀"
            elif avg >= 80:
                grade = "良好"
            elif avg >= 70:
                grade = "中等"
            elif avg >= 60:
                grade = "及格"
            else:
                grade = "不及格"
            info += f"评级: {grade}"
        
        self.stats_text.insert(1.0, info)
    
    def export_image(self):
        if not hasattr(self, 'fig'):
            return
        
        file_path = filedialog.asksaveasfilename(
            defaultextension=".png",
            filetypes=[
                ("PNG图片", "*.png"),
                ("JPG图片", "*.jpg"),
                ("PDF文件", "*.pdf")
            ],
            initialfile=f"{self.current_student}_{self.current_subject}_成绩走势图.png"
        )
        
        if file_path:
            try:
                self.fig.savefig(file_path, dpi=300, bbox_inches='tight')
                messagebox.showinfo("成功", f"图片已保存到:\n{file_path}")
            except Exception as e:
                messagebox.showerror("错误", f"保存失败:\n{str(e)}")

def main():
    root = tk.Tk()
    app = ScoreAnalysisTool(root)
    root.mainloop()

if __name__ == "__main__":
    main()