import tkinter as tk
from tkinter import messagebox, simpledialog
import json
import os

# ======================== 配置 ========================

DATA_FILE = "schedule_data.json"

DAYS = ["周一", "周二", "周三", "周四", "周五"]
MAX_PERIODS = 10  # 每天最多 10 节课

# 默认节次时间
DEFAULT_PERIOD_TIMES = [
    "08:00-08:45", "08:55-09:40", "10:00-10:45", "10:55-11:40",
    "14:00-14:45", "14:55-15:40", "16:00-16:45", "16:55-17:40",
    "19:00-19:45", "19:55-20:40",
]

# 课程颜色池（自动循环分配）
COLOR_POOL = [
    "#FFD6D6", "#D6ECFF", "#D6FFE0", "#FFF3D6", "#E8D6FF",
    "#FFD6F0", "#D6FFF6", "#FFE8CC", "#CCE0FF", "#F0FFD6",
    "#FFCCE0", "#D6D6FF", "#CCFFCC", "#FFE0E0", "#E0F7FA",
]

# ======================== 数据管理 ========================

class ScheduleData:
    """课程表数据管理类，负责加载/保存/增删改"""

    def __init__(self):
        # schedule[day][period] = {"name": "高数", "teacher": "张教授", "location": "A101"}
        self.schedule = {day: {} for day in DAYS}
        self.color_map = {}  # 课程名 -> 颜色
        self.color_index = 0
        self.period_times = list(DEFAULT_PERIOD_TIMES)
        self.load()

    def get_color(self, course_name):
        """为课程名分配/获取固定颜色"""
        if course_name not in self.color_map:
            self.color_map[course_name] = COLOR_POOL[self.color_index % len(COLOR_POOL)]
            self.color_index += 1
        return self.color_map[course_name]

    def add_course(self, day, period, name, teacher, location):
        self.schedule[day][period] = {
            "name": name, "teacher": teacher, "location": location
        }
        self.save()

    def remove_course(self, day, period):
        if period in self.schedule[day]:
            del self.schedule[day][period]
            self.save()

    def get_course(self, day, period):
        return self.schedule[day].get(period, None)

    def save(self):
        data = {
            "schedule": self.schedule,
            "color_map": self.color_map,
            "color_index": self.color_index,
            "period_times": self.period_times,
        }
        try:
            with open(DATA_FILE, "w", encoding="utf-8") as f:
                json.dump(data, f, ensure_ascii=False, indent=2)
        except Exception:
            pass

    def load(self):
        if not os.path.exists(DATA_FILE):
            return
        try:
            with open(DATA_FILE, "r", encoding="utf-8") as f:
                data = json.load(f)
            self.schedule = data.get("schedule", self.schedule)
            self.color_map = data.get("color_map", {})
            self.color_index = data.get("color_index", 0)
            self.period_times = data.get("period_times", DEFAULT_PERIOD_TIMES)
            # 确保所有天都存在
            for day in DAYS:
                if day not in self.schedule:
                    self.schedule[day] = {}
        except Exception:
            pass


# ======================== 添加/编辑课程弹窗 ========================

class CourseDialog(tk.Toplevel):
    """弹窗：输入课程名称、教师、地点"""

    def __init__(self, parent, title="添加课程", default_name="", default_teacher="", default_location=""):
        super().__init__(parent)
        self.title(title)
        self.geometry("340x280")
        self.resizable(False, False)
        self.configure(bg="#f8faff")
        self.transient(parent)
        self.grab_set()

        self.result = None

        # 课程名
        tk.Label(self, text="课程名称:", font=("微软雅黑", 11), bg="#f8faff").pack(pady=(18, 2))
        self.name_var = tk.StringVar(value=default_name)
        tk.Entry(self, textvariable=self.name_var, font=("微软雅黑", 12), width=28,
                 justify="center", relief="solid", bd=1).pack(pady=(0, 8))

        # 教师
        tk.Label(self, text="授课教师:", font=("微软雅黑", 11), bg="#f8faff").pack(pady=(2, 2))
        self.teacher_var = tk.StringVar(value=default_teacher)
        tk.Entry(self, textvariable=self.teacher_var, font=("微软雅黑", 12), width=28,
                 justify="center", relief="solid", bd=1).pack(pady=(0, 8))

        # 地点
        tk.Label(self, text="上课地点:", font=("微软雅黑", 11), bg="#f8faff").pack(pady=(2, 2))
        self.location_var = tk.StringVar(value=default_location)
        tk.Entry(self, textvariable=self.location_var, font=("微软雅黑", 12), width=28,
                 justify="center", relief="solid", bd=1).pack(pady=(0, 15))

        # 按钮
        btn_frame = tk.Frame(self, bg="#f8faff")
        btn_frame.pack(pady=5)

        tk.Button(btn_frame, text="✅ 确认", font=("微软雅黑", 11, "bold"),
                  bg="#3b82f6", fg="white", relief="flat", cursor="hand2",
                  padx=20, pady=4, command=self._confirm).pack(side=tk.LEFT, padx=10)

        tk.Button(btn_frame, text="取消", font=("微软雅黑", 11),
                  bg="#e5e7eb", fg="#333", relief="flat", cursor="hand2",
                  padx=20, pady=4, command=self.destroy).pack(side=tk.LEFT, padx=10)

        self.bind("<Return>", lambda e: self._confirm())
        self.bind("<Escape>", lambda e: self.destroy())

        # 聚焦到课程名输入框
        self.focus_set()
        self.name_entry = self.nametowidget(self.winfo_children()[1])
        self.name_entry.focus_set()

    def _confirm(self):
        name = self.name_var.get().strip()
        if not name:
            messagebox.showwarning("提示", "请输入课程名称！", parent=self)
            return
        self.result = {
            "name": name,
            "teacher": self.teacher_var.get().strip(),
            "location": self.location_var.get().strip(),
        }
        self.destroy()


# ======================== 主界面 ========================

class ScheduleApp:
    def __init__(self, root):
        self.root = root
        self.root.title("📚 我的课程表")
        self.root.configure(bg="#eef2ff")

        self.data = ScheduleData()

        self._build_title()
        self._build_grid()
        self._build_footer()

        self._refresh_grid()

    # ---------- 标题栏 ----------
    def _build_title(self):
        frame = tk.Frame(self.root, bg="#4f46e5", height=60)
        frame.pack(fill=tk.X)
        frame.pack_propagate(False)

        tk.Label(frame, text="📚  我的课程表",
                 font=("微软雅黑", 20, "bold"), fg="white", bg="#4f46e5").pack(side=tk.LEFT, padx=20, expand=True)

        # 清空按钮
        tk.Button(frame, text="🗑️ 清空", font=("微软雅黑", 10),
                  bg="#ef4444", fg="white", activebackground="#dc2626",
                  relief="flat", cursor="hand2", padx=12,
                  command=self._clear_all).pack(side=tk.RIGHT, padx=15)

    # ---------- 课程表网格 ----------
    def _build_grid(self):
        """创建可滚动的课程表网格"""
        # 外层容器
        container = tk.Frame(self.root, bg="#eef2ff")
        container.pack(padx=10, pady=10, fill=tk.BOTH, expand=True)

        # 使用 Canvas + Scrollbar 实现滚动
        canvas = tk.Canvas(container, bg="#eef2ff", highlightthickness=0)
        scrollbar = tk.Scrollbar(container, orient="vertical", command=canvas.yview)
        self.grid_frame = tk.Frame(canvas, bg="#eef2ff")

        self.grid_frame.bind(
            "<Configure>",
            lambda e: canvas.configure(scrollregion=canvas.bbox("all"))
        )

        canvas.create_window((0, 0), window=self.grid_frame, anchor="nw")
        canvas.configure(yscrollcommand=scrollbar.set)

        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

        # 鼠标滚轮支持
        def _on_mousewheel(event):
            canvas.yview_scroll(int(-1 * (event.delta / 120)), "units")
        canvas.bind_all("<MouseWheel>", _on_mousewheel)

        self._draw_header()
        self._draw_cells()

    def _draw_header(self):
        """绘制表头：节次列 + 周一~周五"""
        # 左上角空白
        tk.Label(self.grid_frame, text="节次", font=("微软雅黑", 10, "bold"),
                 bg="#4f46e5", fg="white", width=12, height=2,
                 relief="flat").grid(row=0, column=0, sticky="nsew", padx=1, pady=1)

        for col, day in enumerate(DAYS, start=1):
            tk.Label(self.grid_frame, text=day, font=("微软雅黑", 12, "bold"),
                     bg="#4f46e5", fg="white", width=16, height=2,
                     relief="flat").grid(row=0, column=col, sticky="nsew", padx=1, pady=1)

    def _draw_cells(self):
        """绘制课程格子"""
        self.cell_labels = {}  # (period, day) -> Label

        for period in range(1, MAX_PERIODS + 1):
            row = period  # 第 period 行

            # 节次标签
            time_str = self.data.period_times[period - 1] if period <= len(self.data.period_times) else ""
            header_text = f"第{period}节\n{time_str}"
            tk.Label(self.grid_frame, text=header_text, font=("微软雅黑", 9),
                     bg="#e0e7ff", fg="#4338ca", width=12, height=4,
                     relief="flat", justify="center").grid(
                row=row, column=0, sticky="nsew", padx=1, pady=1
            )

            for col, day in enumerate(DAYS, start=1):
                label = tk.Label(self.grid_frame, text="", font=("微软雅黑", 9),
                                 bg="white", width=16, height=4,
                                 relief="groove", bd=1, justify="center",
                                 cursor="hand2")
                label.grid(row=row, column=col, sticky="nsew", padx=1, pady=1)

                # 绑定事件（用默认参数固定值）
                label.bind("<Button-1>", lambda e, d=day, p=period: self._on_click(d, p))
                label.bind("<Button-3>", lambda e, d=day, p=period: self._on_right_click(d, p))

                self.cell_labels[(period, day)] = label

    def _refresh_grid(self):
        """根据数据刷新所有格子显示"""
        for period in range(1, MAX_PERIODS + 1):
            for day in DAYS:
                label = self.cell_labels[(period, day)]
                course = self.data.get_course(day, period)
                if course:
                    color = self.data.get_color(course["name"])
                    text = f"{course['name']}\n"
                    if course.get("teacher"):
                        text += f"👤 {course['teacher']}\n"
                    if course.get("location"):
                        text += f"📍 {course['location']}"
                    label.config(text=text.strip(), bg=color, fg="#333",
                                 font=("微软雅黑", 9, "bold"))
                else:
                    label.config(text="+", bg="white", fg="#ccc",
                                 font=("微软雅黑", 14))

    # ---------- 事件处理 ----------
    def _on_click(self, day, period):
        """左键点击：添加或编辑课程"""
        course = self.data.get_course(day, period)
        if course:
            # 编辑已有课程
            dialog = CourseDialog(self.root, title=f"编辑课程 - {day} 第{period}节",
                                  default_name=course["name"],
                                  default_teacher=course.get("teacher", ""),
                                  default_location=course.get("location", ""))
        else:
            dialog = CourseDialog(self.root, title=f"添加课程 - {day} 第{period}节")

        self.root.wait_window(dialog)

        if dialog.result:
            self.data.add_course(day, period,
                                 dialog.result["name"],
                                 dialog.result["teacher"],
                                 dialog.result["location"])
            self._refresh_grid()

    def _on_right_click(self, day, period):
        """右键点击：删除课程"""
        course = self.data.get_course(day, period)
        if not course:
            return
        if messagebox.askyesno("确认删除", f"确定要删除「{course['name']}」吗？\n{day} 第{period}节"):
            self.data.remove_course(day, period)
            self._refresh_grid()

    def _clear_all(self):
        """清空全部课程"""
        if messagebox.askyesno("确认清空", "确定要清空所有课程吗？\n此操作不可撤销！"):
            self.data.schedule = {day: {} for day in DAYS}
            self.data.save()
            self._refresh_grid()

    # ---------- 底部提示 ----------
    def _build_footer(self):
        tk.Label(self.root,
                 text="💡 左键点击格子 → 添加/编辑课程  |  右键点击 → 删除课程  |  数据自动保存到本地",
                 font=("微软雅黑", 9), fg="#999", bg="#eef2ff").pack(side="bottom", pady=5)


# ======================== 启动 ========================
if __name__ == "__main__":
    root = tk.Tk()
    root.geometry("900x650")
    root.minsize(800, 500)
    app = ScheduleApp(root)
    root.mainloop()