#!/usr/bin/env python3
"""
╔══════════════════════════════════════════════════════════════════╗
║          🌈 星河日历 · 智能计划表 (Nebula Calendar)              ║
║          特色：毛玻璃拟态 · 动态粒子 · 智能提醒                  ║
╚══════════════════════════════════════════════════════════════════╝
"""

import tkinter as tk
from tkinter import ttk, messagebox, simpledialog, colorchooser
import datetime
import json
import os
import random
import math
import colorsys

# ══════════════════════════════════════════════════════════════════
# 🎨 色彩系统 — 星河主题
# ══════════════════════════════════════════════════════════════════
class NebulaColors:
    """动态色彩系统，支持实时主题切换"""
    THEMES = {
        "🌌 深空紫": {
            "bg_dark": "#0a0015",
            "bg_medium": "#150030",
            "accent1": "#7b2ff7",
            "accent2": "#c084fc",
            "accent3": "#e879f9",
            "glow": "#a78bfa",
            "text_primary": "#f3e8ff",
            "text_secondary": "#c4b5fd",
            "text_dim": "#7c6f9e",
            "glass_bg": "#1e0a3c",
            "glass_border": "#3b1f6e",
            "success": "#4ade80",
            "warning": "#fbbf24",
            "danger": "#f87171",
            "today_ring": "#e879f9",
            "event_colors": ["#7b2ff7", "#ec4899", "#06b6d4", "#f59e0b", "#10b981", "#f43f5e"]
        },
        "🌊 极光蓝": {
            "bg_dark": "#001018",
            "bg_medium": "#002a3d",
            "accent1": "#0891b2",
            "accent2": "#22d3ee",
            "accent3": "#67e8f9",
            "glow": "#06b6d4",
            "text_primary": "#e0f2fe",
            "text_secondary": "#7dd3fc",
            "text_dim": "#5a8a9e",
            "glass_bg": "#0c2540",
            "glass_border": "#164e72",
            "success": "#34d399",
            "warning": "#fbbf24",
            "danger": "#f87171",
            "today_ring": "#22d3ee",
            "event_colors": ["#0891b2", "#3b82f6", "#8b5cf6", "#06b6d4", "#10b981", "#f43f5e"]
        },
        "🔥 熔岩橙": {
            "bg_dark": "#1a0a00",
            "bg_medium": "#2d1600",
            "accent1": "#ea580c",
            "accent2": "#fb923c",
            "accent3": "#fdba74",
            "glow": "#f97316",
            "text_primary": "#fff7ed",
            "text_secondary": "#fed7aa",
            "text_dim": "#9a7a5e",
            "glass_bg": "#2a1500",
            "glass_border": "#7c2d12",
            "success": "#4ade80",
            "warning": "#fbbf24",
            "danger": "#f87171",
            "today_ring": "#fb923c",
            "event_colors": ["#ea580c", "#dc2626", "#f59e0b", "#84cc16", "#06b6d4", "#8b5cf6"]
        },
        "🌿 翡翠绿": {
            "bg_dark": "#001a0d",
            "bg_medium": "#003321",
            "accent1": "#059669",
            "accent2": "#34d399",
            "accent3": "#6ee7b7",
            "glow": "#10b981",
            "text_primary": "#ecfdf5",
            "text_secondary": "#a7f3d0",
            "text_dim": "#5a8a6e",
            "glass_bg": "#0a2518",
            "glass_border": "#065f46",
            "success": "#4ade80",
            "warning": "#fbbf24",
            "danger": "#f87171",
            "today_ring": "#34d399",
            "event_colors": ["#059669", "#0891b2", "#3b82f6", "#8b5cf6", "#f59e0b", "#f43f5e"]
        }
    }


# ══════════════════════════════════════════════════════════════════
# ✨ 背景画布 — 动态粒子 + 渐变星空
# ══════════════════════════════════════════════════════════════════
class ParticleField:
    """动态粒子星空背景"""
    def __init__(self, canvas, width, height, colors):
        self.canvas = canvas
        self.width = width
        self.height = height
        self.colors = colors
        self.particles = []
        self.running = True
        self._init_particles()

    def _init_particles(self):
        self.particles = []
        for _ in range(60):
            p = {
                'x': random.uniform(0, self.width),
                'y': random.uniform(0, self.height),
                'r': random.uniform(0.5, 2.5),
                'speed': random.uniform(0.2, 1.5),
                'angle': random.uniform(0, math.pi * 2),
                'twinkle_speed': random.uniform(0.02, 0.08),
                'twinkle_phase': random.uniform(0, math.pi * 2),
                'color_idx': random.randint(0, 2)
            }
            self.particles.append(p)

    def draw_gradient_bg(self):
        """绘制深空渐变背景"""
        c = self.colors
        # 多层渐变模拟
        steps = 40
        for i in range(steps):
            t = i / steps
            r = int(int(c["bg_dark"][1:3], 16) * (1-t) + int(c["bg_medium"][1:3], 16) * t)
            g = int(int(c["bg_dark"][3:5], 16) * (1-t) + int(c["bg_medium"][3:5], 16) * t)
            b = int(int(c["bg_dark"][5:7], 16) * (1-t) + int(c["bg_medium"][5:7], 16) * t)
            color = f"#{r:02x}{g:02x}{b:02x}"
            y1 = int(self.height * i / steps)
            y2 = int(self.height * (i+1) / steps)
            self.canvas.create_rectangle(0, y1, self.width, y2, fill=color, outline="")

    def draw_orbital_glow(self):
        """绘制装饰性光晕"""
        c = self.colors
        # 左上角光晕
        for i in range(5):
            r = 80 + i * 30
            alpha_color = self._hex_to_bright(c["accent1"], 0.08 - i*0.015)
            self.canvas.create_oval(
                100 - r, 80 - r, 100 + r, 80 + r,
                fill=alpha_color, outline=""
            )
        # 右下角光晕
        for i in range(4):
            r = 60 + i * 25
            alpha_color = self._hex_to_bright(c["accent2"], 0.06 - i*0.012)
            self.canvas.create_oval(
                self.width - 120 - r, self.height - 100 - r,
                self.width - 120 + r, self.height - 100 + r,
                fill=alpha_color, outline=""
            )

    def _hex_to_bright(self, hex_color, factor=0.3):
        """提亮颜色模拟发光"""
        r = int(hex_color[1:3], 16)
        g = int(hex_color[3:5], 16)
        b = int(hex_color[5:7], 16)
        r = int(r + (255 - r) * factor)
        g = int(g + (255 - g) * factor)
        b = int(b + (255 - b) * factor)
        return f"#{r:02x}{g:02x}{b:02x}"

    def update(self):
        """更新粒子动画"""
        if not self.running:
            return
        self.canvas.delete("particle")
        c = self.colors
        color_list = [c["accent2"], c["accent3"], c["glow"]]

        for p in self.particles:
            # 移动
            p['x'] += math.cos(p['angle']) * p['speed']
            p['y'] += math.sin(p['angle']) * p['speed']
            # 边界回绕
            if p['x'] < 0: p['x'] = self.width
            if p['x'] > self.width: p['x'] = 0
            if p['y'] < 0: p['y'] = self.height
            if p['y'] > self.height: p['y'] = 0
            # 闪烁
            p['twinkle_phase'] += p['twinkle_speed']
            brightness = 0.5 + 0.5 * math.sin(p['twinkle_phase'])
            # 绘制
            base_color = color_list[p['color_idx']]
            r = int(base_color[1:3], 16)
            g = int(base_color[3:5], 16)
            b = int(base_color[5:7], 16)
            r = int(r * brightness + 255 * (1-brightness) * 0.3)
            g = int(g * brightness + 255 * (1-brightness) * 0.3)
            b = int(b * brightness + 255 * (1-brightness) * 0.3)
            draw_color = f"#{r:02x}{g:02x}{b:02x}"
            size = p['r'] * (0.5 + 0.5 * brightness)
            self.canvas.create_oval(
                p['x']-size, p['y']-size, p['x']+size, p['y']+size,
                fill=draw_color, outline="", tags="particle"
            )

    def start_animation(self, root, interval=50):
        def loop():
            self.update()
            root.after(interval, loop)
        loop()


# ══════════════════════════════════════════════════════════════════
# 📅 日历核心逻辑
# ══════════════════════════════════════════════════════════════════
class CalendarCore:
    """日历数据管理"""
    WEEKDAYS_CN = ["一", "二", "三", "四", "五", "六", "日"]
    MONTHS_CN = ["一月", "二月", "三月", "四月", "五月", "六月",
                 "七月", "八月", "九月", "十月", "十一月", "十二月"]

    def __init__(self):
        self.today = datetime.date.today()
        self.selected_date = self.today
        self.view_year = self.today.year
        self.view_month = self.today.month
        self.events = {}  # {date_str: [event_dict, ...]}
        self.load_events()

    def get_month_matrix(self, year, month):
        """获取月历矩阵 (6x7)"""
        cal = []
        first_day = datetime.date(year, month, 1)
        if month == 12:
            last_day = datetime.date(year + 1, 1, 1) - datetime.timedelta(days=1)
        else:
            last_day = datetime.date(year, month + 1, 1) - datetime.timedelta(days=1)

        # 月初偏移 (Monday=0)
        start_offset = first_day.weekday()
        days_in_month = last_day.day

        day = 1
        for week in range(6):
            row = []
            for col in range(7):
                cell_day = week * 7 + col - start_offset + 1
                if 1 <= cell_day <= days_in_month:
                    row.append(cell_day)
                else:
                    row.append(None)
            cal.append(row)
            if day + 7 > days_in_month:
                break
            day += 7
        return cal

    def date_str(self, year, month, day):
        return f"{year}-{month:02d}-{day:02d}"

    def add_event(self, date_str, title, time_str="", category="默认", color_idx=0, note=""):
        event = {
            "title": title,
            "time": time_str,
            "category": category,
            "color_idx": color_idx,
            "note": note,
            "created": datetime.datetime.now().strftime("%Y-%m-%d %H:%M")
        }
        if date_str not in self.events:
            self.events[date_str] = []
        self.events[date_str].append(event)
        self.save_events()

    def delete_event(self, date_str, event_index):
        if date_str in self.events and 0 <= event_index < len(self.events[date_str]):
            self.events[date_str].pop(event_index)
            if not self.events[date_str]:
                del self.events[date_str]
            self.save_events()

    def get_events(self, date_str):
        return self.events.get(date_str, [])

    def get_upcoming_events(self, days=7):
        """获取即将到来的事件"""
        upcoming = []
        for i in range(days):
            d = self.today + datetime.timedelta(days=i)
            ds = self.date_str(d.year, d.month, d.day)
            if ds in self.events:
                for ev in self.events[ds]:
                    ev_copy = ev.copy()
                    ev_copy['date'] = ds
                    ev_copy['days_left'] = i
                    upcoming.append(ev_copy)
        return upcoming

    def save_events(self):
        try:
            with open("nebula_events.json", "w", encoding="utf-8") as f:
                json.dump(self.events, f, ensure_ascii=False, indent=2)
        except:
            pass

    def load_events(self):
        try:
            if os.path.exists("nebula_events.json"):
                with open("nebula_events.json", "r", encoding="utf-8") as f:
                    self.events = json.load(f)
        except:
            self.events = {}


# ══════════════════════════════════════════════════════════════════
# 🎯 主应用
# ══════════════════════════════════════════════════════════════════
class NebulaCalendarApp:
    """星河日历主应用"""

    def __init__(self, root):
        self.root = root
        self.root.title("🌈 星河日历 · 智能计划表")
        self.root.geometry("1100x720")
        self.root.minsize(1000, 650)
        self.root.configure(bg="#0a0015")

        # 当前主题
        self.current_theme = "🌌 深空紫"
        self.C = NebulaColors.THEMES[self.current_theme]

        # 日历核心
        self.cal = CalendarCore()

        # 分类管理
        self.categories = ["💼 工作", "📚 学习", "🏃 运动", "🎨 创作", "💖 生活", "🎯 目标"]
        self.cat_colors = [0, 1, 2, 3, 4, 5]

        # 窗口居中
        self._center_window()

        # 构建UI
        self._build_ui()

        # 启动粒子动画
        self.particles.start_animation(self.root)

        # 启动时钟
        self._update_clock()

        # 绑定窗口大小变化
        self.root.bind("<Configure>", self._on_resize)

    def _center_window(self):
        self.root.update_idletasks()
        w = 1100
        h = 720
        x = (self.root.winfo_screenwidth() // 2) - (w // 2)
        y = (self.root.winfo_screenheight() // 2) - (h // 2)
        self.root.geometry(f"{w}x{h}+{x}+{y}")

    def _on_resize(self, event):
        if event.widget == self.root:
            self.canvas.configure(width=event.width, height=event.height)
            self.particles.width = event.width
            self.particles.height = event.height

    def _build_ui(self):
        """构建完整UI"""
        # ── 背景画布（最底层）──
        self.canvas = tk.Canvas(self.root, highlightthickness=0)
        self.canvas.place(x=0, y=0, relwidth=1, relheight=1)
        self.particles = ParticleField(self.canvas, 1100, 720, self.C)
        self.particles.draw_gradient_bg()
        self.particles.draw_orbital_glow()

        # ── 主容器 ──
        self.main_container = tk.Frame(self.root, bg=self.C["bg_dark"], highlightthickness=0)
        self.main_container.place(relx=0.02, rely=0.02, relwidth=0.96, relheight=0.96)

        # ── 顶部栏 ──
        self._build_top_bar()

        # ── 中间区域 ──
        self.content_frame = tk.Frame(self.main_container, bg=self.C["bg_dark"])
        self.content_frame.pack(fill="both", expand=True, padx=10, pady=(0, 10))

        # 左侧：日历
        self._build_calendar_panel()
        # 右侧：事件面板
        self._build_event_panel()

        # ── 底部状态栏 ──
        self._build_status_bar()

        # 刷新日历显示
        self.refresh_calendar()

    def _build_top_bar(self):
        """构建顶部标题栏"""
        top = tk.Frame(self.main_container, bg=self.C["bg_dark"], height=70)
        top.pack(fill="x", padx=10, pady=(10, 5))
        top.pack_propagate(False)

        # 左侧：标题 + 时钟
        left = tk.Frame(top, bg=self.C["bg_dark"])
        left.pack(side="left", fill="y")

        self.title_label = tk.Label(
            left, text="✦ 星河日历", font=("WenQuanYi Micro Hei", 26, "bold"),
            fg=self.C["accent3"], bg=self.C["bg_dark"]
        )
        self.title_label.pack(anchor="w")

        self.clock_label = tk.Label(
            left, text="", font=("WenQuanYi Micro Hei", 11),
            fg=self.C["text_dim"], bg=self.C["bg_dark"]
        )
        self.clock_label.pack(anchor="w", pady=(2, 0))

        # 中间：年月导航
        nav = tk.Frame(top, bg=self.C["bg_dark"])
        nav.pack(side="left", padx=40, fill="y")

        self.prev_btn = tk.Button(
            nav, text="◀", font=("WenQuanYi Micro Hei", 16, "bold"),
            fg=self.C["accent2"], bg=self.C["glass_bg"],
            activeforeground=self.C["accent3"], activebackground=self.C["glass_border"],
            relief="flat", bd=0, padx=12, pady=4, cursor="hand2",
            command=self._prev_month
        )
        self.prev_btn.pack(side="left", pady=15)

        self.month_label = tk.Label(
            nav, text="", font=("WenQuanYi Micro Hei", 22, "bold"),
            fg=self.C["text_primary"], bg=self.C["bg_dark"], width=14
        )
        self.month_label.pack(side="left", padx=10, pady=15)

        self.next_btn = tk.Button(
            nav, text="▶", font=("WenQuanYi Micro Hei", 16, "bold"),
            fg=self.C["accent2"], bg=self.C["glass_bg"],
            activeforeground=self.C["accent3"], activebackground=self.C["glass_border"],
            relief="flat", bd=0, padx=12, pady=4, cursor="hand2",
            command=self._next_month
        )
        self.next_btn.pack(side="left", pady=15)

        # 回到今天
        self.today_btn = tk.Button(
            nav, text="📍今天", font=("WenQuanYi Micro Hei", 11, "bold"),
            fg=self.C["bg_dark"], bg=self.C["accent3"],
            activebackground=self.C["accent2"], relief="flat", bd=0,
            padx=10, pady=3, cursor="hand2", command=self._go_today
        )
        self.today_btn.pack(side="left", padx=15, pady=15)

        # 右侧：主题切换 + 添加事件
        right = tk.Frame(top, bg=self.C["bg_dark"])
        right.pack(side="right", fill="y")

        self.theme_btn = tk.Button(
            right, text="🎨 主题", font=("WenQuanYi Micro Hei", 11, "bold"),
            fg=self.C["text_primary"], bg=self.C["glass_bg"],
            activebackground=self.C["glass_border"], relief="flat", bd=0,
            padx=10, pady=5, cursor="hand2", command=self._show_theme_menu
        )
        self.theme_btn.pack(side="left", pady=18, padx=(0, 8))

        self.add_btn = tk.Button(
            right, text="➕ 添加计划", font=("WenQuanYi Micro Hei", 12, "bold"),
            fg=self.C["bg_dark"], bg=self.C["accent3"],
            activebackground=self.C["accent2"], relief="flat", bd=0,
            padx=14, pady=6, cursor="hand2", command=self._add_event_dialog
        )
        self.add_btn.pack(side="left", pady=15)

    def _build_calendar_panel(self):
        """构建左侧日历面板 — 毛玻璃效果"""
        cal_outer = tk.Frame(self.content_frame, bg=self.C["bg_dark"])
        cal_outer.pack(side="left", fill="both", expand=True, padx=(0, 8))

        # 毛玻璃容器
        self.cal_frame = tk.Frame(
            cal_outer, bg=self.C["glass_bg"],
            highlightbackground=self.C["glass_border"],
            highlightthickness=1
        )
        self.cal_frame.pack(fill="both", expand=True, padx=5, pady=5)

        # 星期标题行
        self.weekday_frame = tk.Frame(self.cal_frame, bg=self.C["glass_bg"])
        self.weekday_frame.pack(fill="x", padx=8, pady=(10, 4))

        # 日期网格容器
        self.days_frame = tk.Frame(self.cal_frame, bg=self.C["glass_bg"])
        self.days_frame.pack(fill="both", expand=True, padx=8, pady=(0, 8))

        # 存储日期按钮引用
        self.day_buttons = []

    def _build_event_panel(self):
        """构建右侧事件面板"""
        event_outer = tk.Frame(self.content_frame, bg=self.C["bg_dark"], width=360)
        event_outer.pack(side="right", fill="both", padx=(8, 0))
        event_outer.pack_propagate(False)

        # 毛玻璃容器
        self.event_frame = tk.Frame(
            event_outer, bg=self.C["glass_bg"],
            highlightbackground=self.C["glass_border"],
            highlightthickness=1
        )
        self.event_frame.pack(fill="both", expand=True, padx=5, pady=5)

        # 选中日期标题
        self.selected_label = tk.Label(
            self.event_frame, text="", font=("WenQuanYi Micro Hei", 16, "bold"),
            fg=self.C["accent3"], bg=self.C["glass_bg"]
        )
        self.selected_label.pack(anchor="w", padx=15, pady=(15, 5))

        # 分隔线
        sep = tk.Frame(self.event_frame, height=1, bg=self.C["glass_border"])
        sep.pack(fill="x", padx=15, pady=5)

        # 事件列表区域（Canvas + Scrollbar）
        list_area = tk.Frame(self.event_frame, bg=self.C["glass_bg"])
        list_area.pack(fill="both", expand=True, padx=10, pady=5)

        self.event_canvas = tk.Canvas(list_area, bg=self.C["glass_bg"], highlightthickness=0)
        self.event_scrollbar = tk.Scrollbar(list_area, orient="vertical", command=self.event_canvas.yview)
        self.event_scrollbar.pack(side="right", fill="y")
        self.event_canvas.pack(side="left", fill="both", expand=True)
        self.event_canvas.configure(yscrollcommand=self.event_scrollbar.set)

        self.event_list_frame = tk.Frame(self.event_canvas, bg=self.C["glass_bg"])
        self.event_canvas.create_window((0, 0), window=self.event_list_frame, anchor="nw")
        self.event_list_frame.bind(
            "<Configure>",
            lambda e: self.event_canvas.configure(scrollregion=self.event_canvas.bbox("all"))
        )

        # 即将到来区域
        self.upcoming_label = tk.Label(
            self.event_frame, text="🔮 即将到来", font=("WenQuanYi Micro Hei", 13, "bold"),
            fg=self.C["accent2"], bg=self.C["glass_bg"]
        )
        self.upcoming_label.pack(anchor="w", padx=15, pady=(10, 5))

        self.upcoming_canvas = tk.Canvas(self.event_frame, bg=self.C["glass_bg"], highlightthickness=0, height=150)
        self.upcoming_canvas.pack(fill="x", padx=10, pady=(0, 10))

    def _build_status_bar(self):
        """底部状态栏"""
        self.status_bar = tk.Frame(self.main_container, bg=self.C["bg_dark"], height=28)
        self.status_bar.pack(fill="x", padx=10, pady=(5, 0))

        self.status_label = tk.Label(
            self.status_bar, text="", font=("WenQuanYi Micro Hei", 10),
            fg=self.C["text_dim"], bg=self.C["bg_dark"]
        )
        self.status_label.pack(side="left")

        self.event_count_label = tk.Label(
            self.status_bar, text="", font=("WenQuanYi Micro Hei", 10),
            fg=self.C["accent2"], bg=self.C["bg_dark"]
        )
        self.event_count_label.pack(side="right")

    # ──────────────────────────────────────────────
    # 🔄 日历渲染
    # ──────────────────────────────────────────────
    def refresh_calendar(self):
        """刷新日历显示"""
        # 更新月份标签
        month_text = f"{self.cal.view_year} 年 {CalendarCore.MONTHS_CN[self.cal.view_month - 1]}"
        self.month_label.config(text=month_text)

        # 更新星期标题
        for widget in self.weekday_frame.winfo_children():
            widget.destroy()

        for i, wd in enumerate(CalendarCore.WEEKDAYS_CN):
            color = self.C["accent3"] if i >= 5 else self.C["text_secondary"]
            lbl = tk.Label(
                self.weekday_frame, text=wd, font=("WenQuanYi Micro Hei", 12, "bold"),
                fg=color, bg=self.C["glass_bg"], width=4
            )
            lbl.grid(row=0, column=i, padx=2, pady=2)

        # 更新日期网格
        for widget in self.days_frame.winfo_children():
            widget.destroy()

        self.day_buttons = []
        matrix = self.cal.get_month_matrix(self.cal.view_year, self.cal.view_month)

        for week_idx, week in enumerate(matrix):
            for col_idx, day in enumerate(week):
                cell_frame = tk.Frame(self.days_frame, bg=self.C["glass_bg"])
                cell_frame.grid(row=week_idx, column=col_idx, padx=2, pady=2, sticky="nsew")

                if day is None:
                    lbl = tk.Label(cell_frame, text="", bg=self.C["glass_bg"])
                    lbl.pack(fill="both", expand=True)
                    continue

                date_str = self.cal.date_str(self.cal.view_year, self.cal.view_month, day)
                is_today = (self.cal.view_year == self.cal.today.year and
                           self.cal.view_month == self.cal.today.month and
                           day == self.cal.today.day)
                is_selected = (self.cal.selected_date.year == self.cal.view_year and
                              self.cal.selected_date.month == self.cal.view_month and
                              self.cal.selected_date.day == day)
                is_weekend = col_idx >= 5
                has_events = date_str in self.cal.events

                # 颜色逻辑
                if is_selected:
                    btn_bg = self.C["accent1"]
                    btn_fg = "#ffffff"
                    relief = "solid"
                    bd = 2
                elif is_today:
                    btn_bg = self.C["glass_border"]
                    btn_fg = self.C["today_ring"]
                    relief = "solid"
                    bd = 2
                else:
                    btn_bg = self.C["bg_medium"]
                    btn_fg = self.C["accent3"] if is_weekend else self.C["text_primary"]
                    relief = "flat"
                    bd = 0

                # 事件指示点颜色
                dot_color = self.C["accent3"]
                if has_events:
                    events = self.cal.get_events(date_str)
                    if events:
                        color_idx = events[0].get("color_idx", 0)
                        ec = self.C["event_colors"]
                        if color_idx < len(ec):
                            dot_color = ec[color_idx]

                btn = tk.Button(
                    cell_frame, text=str(day),
                    font=("WenQuanYi Micro Hei", 13, "bold" if is_today or is_selected else "normal"),
                    fg=btn_fg, bg=btn_bg,
                    activebackground=self.C["accent2"], activeforeground="#000000",
                    relief=relief, bd=bd,
                    highlightbackground=self.C["today_ring"] if is_today else btn_bg,
                    cursor="hand2",
                    command=lambda d=day: self._select_date(d)
                )
                btn.pack(fill="both", expand=True, padx=1, pady=1)

                # 事件指示点
                if has_events:
                    dot_frame = tk.Frame(cell_frame, bg=btn_bg, height=4)
                    dot_frame.place(relx=0.5, rely=0.85, anchor="center")
                    dot = tk.Frame(dot_frame, bg=dot_color, width=6, height=3)
                    dot.pack()

                self.day_buttons.append(btn)

        # 配置网格权重
        for i in range(7):
            self.days_frame.grid_columnconfigure(i, weight=1, uniform="col")
        for i in range(len(matrix)):
            self.days_frame.grid_rowconfigure(i, weight=1, uniform="row")

        # 刷新事件面板
        self._refresh_event_panel()
        self._refresh_upcoming()
        self._refresh_status()

    def _select_date(self, day):
        """选择日期"""
        self.cal.selected_date = datetime.date(self.cal.view_year, self.cal.view_month, day)
        self.refresh_calendar()

    def _prev_month(self):
        if self.cal.view_month == 1:
            self.cal.view_month = 12
            self.cal.view_year -= 1
        else:
            self.cal.view_month -= 1
        self.refresh_calendar()

    def _next_month(self):
        if self.cal.view_month == 12:
            self.cal.view_month = 1
            self.cal.view_year += 1
        else:
            self.cal.view_month += 1
        self.refresh_calendar()

    def _go_today(self):
        self.cal.view_year = self.cal.today.year
        self.cal.view_month = self.cal.today.month
        self.cal.selected_date = self.cal.today
        self.refresh_calendar()

    # ──────────────────────────────────────────────
    # 📋 事件面板
    # ──────────────────────────────────────────────
    def _refresh_event_panel(self):
        """刷新右侧事件列表"""
        for widget in self.event_list_frame.winfo_children():
            widget.destroy()

        sd = self.cal.selected_date
        date_str = self.cal.date_str(sd.year, sd.month, sd.day)
        weekday_names = ["周一", "周二", "周三", "周四", "周五", "周六", "周日"]
        wd_name = weekday_names[sd.weekday()]

        self.selected_label.config(
            text=f"📅 {sd.month}月{sd.day}日 {wd_name}"
        )

        events = self.cal.get_events(date_str)

        if not events:
            empty_frame = tk.Frame(self.event_list_frame, bg=self.C["glass_bg"])
            empty_frame.pack(fill="x", pady=20)

            tk.Label(
                empty_frame, text="🌙", font=("WenQuanYi Micro Hei", 32),
                fg=self.C["text_dim"], bg=self.C["glass_bg"]
            ).pack()
            tk.Label(
                empty_frame, text="这一天很清闲\n点击「添加计划」来安排吧",
                font=("WenQuanYi Micro Hei", 11),
                fg=self.C["text_dim"], bg=self.C["glass_bg"], justify="center"
            ).pack(pady=(5, 0))
        else:
            for idx, event in enumerate(events):
                self._create_event_card(idx, event, date_str)

    def _create_event_card(self, idx, event, date_str):
        """创建单个事件卡片"""
        ec = self.C["event_colors"]
        color_idx = event.get("color_idx", 0)
        accent = ec[color_idx % len(ec)] if ec else self.C["accent2"]

        card = tk.Frame(
            self.event_list_frame, bg=self.C["bg_medium"],
            highlightbackground=accent, highlightthickness=2
        )
        card.pack(fill="x", pady=4, padx=2)

        # 左侧色条
        bar = tk.Frame(card, bg=accent, width=4)
        bar.pack(side="left", fill="y")

        # 内容区
        content = tk.Frame(card, bg=self.C["bg_medium"])
        content.pack(side="left", fill="both", expand=True, padx=8, pady=6)

        # 标题行
        title_row = tk.Frame(content, bg=self.C["bg_medium"])
        title_row.pack(fill="x")

        tk.Label(
            title_row, text=event.get("title", "无标题"),
            font=("WenQuanYi Micro Hei", 12, "bold"),
            fg=self.C["text_primary"], bg=self.C["bg_medium"], anchor="w"
        ).pack(side="left")

        # 删除按钮
        del_btn = tk.Button(
            title_row, text="✕", font=("WenQuanYi Micro Hei", 10),
            fg=self.C["text_dim"], bg=self.C["bg_medium"],
            activeforeground=self.C["danger"], activebackground=self.C["bg_medium"],
            relief="flat", bd=0, cursor="hand2", padx=4,
            command=lambda i=idx, ds=date_str: self._delete_event(i, ds)
        )
        del_btn.pack(side="right")

        # 时间和分类
        info_parts = []
        if event.get("time"):
            info_parts.append(f"🕐 {event['time']}")
        if event.get("category"):
            info_parts.append(event["category"])

        if info_parts:
            tk.Label(
                content, text="  ·  ".join(info_parts),
                font=("WenQuanYi Micro Hei", 9),
                fg=self.C["text_secondary"], bg=self.C["bg_medium"], anchor="w"
            ).pack(anchor="w", pady=(2, 0))

        # 备注
        if event.get("note"):
            tk.Label(
                content, text=event["note"],
                font=("WenQuanYi Micro Hei", 9),
                fg=self.C["text_dim"], bg=self.C["bg_medium"], anchor="w",
                wraplength=280, justify="left"
            ).pack(anchor="w", pady=(2, 0))

    def _refresh_upcoming(self):
        """刷新即将到来区域"""
        self.upcoming_canvas.delete("all")
        upcoming = self.cal.get_upcoming_events(days=7)

        if not upcoming:
            self.upcoming_canvas.create_text(
                175, 50, text="🎉 未来一周暂无安排",
                font=("WenQuanYi Micro Hei", 11), fill=self.C["text_dim"]
            )
            return

        y = 8
        for ev in upcoming[:5]:
            ec = self.C["event_colors"]
            accent = ec[ev.get("color_idx", 0) % len(ec)]
            days_left = ev["days_left"]

            # 色条
            self.upcoming_canvas.create_rectangle(10, y, 14, y+28, fill=accent, outline="")

            # 标题
            title_text = ev.get("title", "")[:20]
            self.upcoming_canvas.create_text(
                22, y+6, text=title_text,
                font=("WenQuanYi Micro Hei", 10, "bold"),
                fill=self.C["text_primary"], anchor="nw"
            )

            # 日期信息
            date_obj = datetime.date.fromisoformat(ev["date"])
            if days_left == 0:
                day_text = "今天"
            elif days_left == 1:
                day_text = "明天"
            else:
                day_text = f"{days_left}天后"

            time_text = ev.get("time", "")
            full_text = f"{day_text} · {date_obj.month}/{date_obj.day}"
            if time_text:
                full_text += f" · {time_text}"

            self.upcoming_canvas.create_text(
                22, y+20, text=full_text,
                font=("WenQuanYi Micro Hei", 8),
                fill=self.C["text_dim"], anchor="nw"
            )
            y += 32

    def _refresh_status(self):
        """刷新状态栏"""
        total_events = sum(len(v) for v in self.cal.events.values())
        today_str = self.cal.date_str(self.cal.today.year, self.cal.today.month, self.cal.today.day)
        today_count = len(self.cal.get_events(today_str))

        self.status_label.config(text=f"💡 提示：点击日期选择 · 双击日期快速添加")
        self.event_count_label.config(
            text=f"📊 今日 {today_count} 项 · 总计 {total_events} 项计划"
        )

    # ──────────────────────────────────────────────
    # ➕ 事件操作
    # ──────────────────────────────────────────────
    def _add_event_dialog(self):
        """添加事件对话框"""
        sd = self.cal.selected_date
        dialog = EventDialog(
            self.root, "➕ 新建计划",
            default_date=sd, categories=self.categories,
            colors=self.C, theme_name=self.current_theme
        )
        result = dialog.show()

        if result:
            date_str = self.cal.date_str(result["year"], result["month"], result["day"])
            self.cal.add_event(
                date_str,
                title=result["title"],
                time_str=result["time"],
                category=result["category"],
                color_idx=result["color_idx"],
                note=result["note"]
            )
            self.refresh_calendar()
            self._show_toast(f"✅ 已添加：{result['title']}")

    def _delete_event(self, idx, date_str):
        """删除事件"""
        events = self.cal.get_events(date_str)
        if 0 <= idx < len(events):
            title = events[idx].get("title", "该事件")
            self.cal.delete_event(date_str, idx)
            self.refresh_calendar()
            self._show_toast(f"🗑️ 已删除：{title}")

    # ──────────────────────────────────────────────
    # 🎨 主题切换
    # ──────────────────────────────────────────────
    def _show_theme_menu(self):
        """显示主题菜单"""
        menu = tk.Menu(self.root, tearoff=0,
                      bg=self.C["glass_bg"], fg=self.C["text_primary"],
                      activebackground=self.C["accent1"], activeforeground="#fff",
                      font=("WenQuanYi Micro Hei", 11))
        for theme_name in NebulaColors.THEMES:
            menu.add_command(
                label=theme_name,
                command=lambda t=theme_name: self._switch_theme(t)
            )
        # 在按钮下方显示
        menu.post(
            self.theme_btn.winfo_rootx(),
            self.theme_btn.winfo_rooty() + self.theme_btn.winfo_height()
        )

    def _switch_theme(self, theme_name):
        """切换主题"""
        self.current_theme = theme_name
        self.C = NebulaColors.THEMES[theme_name]
        self.cal.save_events()  # 顺便保存

        # 重新配置所有组件颜色
        self._rebuild_ui_colors()
        self.refresh_calendar()
        self._show_toast(f"🎨 已切换主题：{theme_name}")

    def _rebuild_ui_colors(self):
        """重建UI颜色"""
        self.root.configure(bg=self.C["bg_dark"])
        self.main_container.configure(bg=self.C["bg_dark"])
        self.content_frame.configure(bg=self.C["bg_dark"])
        self.status_bar.configure(bg=self.C["bg_dark"])
        self.status_label.configure(bg=self.C["bg_dark"], fg=self.C["text_dim"])
        self.event_count_label.configure(bg=self.C["bg_dark"], fg=self.C["accent2"])

        # 标题
        self.title_label.configure(fg=self.C["accent3"], bg=self.C["bg_dark"])
        self.clock_label.configure(bg=self.C["bg_dark"], fg=self.C["text_dim"])
        self.month_label.configure(bg=self.C["bg_dark"], fg=self.C["text_primary"])

        # 按钮
        for btn, text in [(self.prev_btn, "◀"), (self.next_btn, "▶")]:
            btn.configure(
                fg=self.C["accent2"], bg=self.C["glass_bg"],
                activeforeground=self.C["accent3"], activebackground=self.C["glass_border"]
            )
        self.today_btn.configure(fg=self.C["bg_dark"], bg=self.C["accent3"])
        self.theme_btn.configure(fg=self.C["text_primary"], bg=self.C["glass_bg"])
        self.add_btn.configure(fg=self.C["bg_dark"], bg=self.C["accent3"])

        # 日历框架
        self.cal_frame.configure(bg=self.C["glass_bg"],
                               highlightbackground=self.C["glass_border"])
        self.weekday_frame.configure(bg=self.C["glass_bg"])
        self.days_frame.configure(bg=self.C["glass_bg"])

        # 事件面板
        self.event_frame.configure(bg=self.C["glass_bg"],
                                  highlightbackground=self.C["glass_border"])
        self.selected_label.configure(fg=self.C["accent3"], bg=self.C["glass_bg"])
        self.upcoming_label.configure(fg=self.C["accent2"], bg=self.C["glass_bg"])
        self.event_canvas.configure(bg=self.C["glass_bg"])
        self.event_list_frame.configure(bg=self.C["glass_bg"])

        # 重绘背景
        self.canvas.delete("all")
        self.particles.colors = self.C
        self.particles.draw_gradient_bg()
        self.particles.draw_orbital_glow()

    # ──────────────────────────────────────────────
    # ⏰ 时钟 & 提示
    # ──────────────────────────────────────────────
    def _update_clock(self):
        """更新时钟"""
        now = datetime.datetime.now()
        text = f"🕐 {now.strftime('%Y-%m-%d %H:%M:%S')}  |  {self.current_theme}"
        self.clock_label.config(text=text)
        self.root.after(1000, self._update_clock)

    def _show_toast(self, message):
        """显示临时提示"""
        toast = tk.Toplevel(self.root)
        toast.overrideredirect(True)
        toast.configure(bg=self.C["accent1"])
        toast.attributes("-alpha", 0.9)

        tk.Label(
            toast, text=message, font=("WenQuanYi Micro Hei", 12, "bold"),
            fg="#ffffff", bg=self.C["accent1"], padx=20, pady=8
        ).pack()

        # 定位到窗口底部中央
        self.root.update_idletasks()
        rx = self.root.winfo_rootx()
        rw = self.root.winfo_width()
        toast.geometry(f"+{rx + rw//2 - 100}+{self.root.winfo_rooty() + self.root.winfo_height() - 80}")

        # 3秒后消失
        toast.after(2500, toast.destroy)


# ══════════════════════════════════════════════════════════════════
# 💬 事件编辑对话框
# ══════════════════════════════════════════════════════════════════
class EventDialog:
    """自定义事件编辑对话框"""

    def __init__(self, parent, title, default_date=None, categories=None, colors=None, theme_name=""):
        self.parent = parent
        self.title = title
        self.default_date = default_date or datetime.date.today()
        self.categories = categories or ["默认"]
        self.C = colors or NebulaColors.THEMES["🌌 深空紫"]
        self.result = None

        self.dialog = tk.Toplevel(parent)
        self.dialog.title(title)
        self.dialog.geometry("420x440")
        self.dialog.configure(bg=self.C["bg_dark"])
        self.dialog.resizable(False, False)
        self.dialog.transient(parent)
        self.dialog.grab_set()

        # 居中
        self.dialog.update_idletasks()
        px = parent.winfo_rootx()
        py = parent.winfo_rooty()
        pw = parent.winfo_width()
        ph = parent.winfo_height()
        x = px + (pw - 420) // 2
        y = py + (ph - 440) // 2
        self.dialog.geometry(f"420x440+{x}+{y}")

        self._build_dialog()

    def _build_dialog(self):
        # 标题
        tk.Label(
            self.dialog, text=self.title, font=("WenQuanYi Micro Hei", 18, "bold"),
            fg=self.C["accent3"], bg=self.C["bg_dark"]
        ).pack(pady=(20, 15))

        # 毛玻璃区域
        form = tk.Frame(self.dialog, bg=self.C["glass_bg"],
                       highlightbackground=self.C["glass_border"], highlightthickness=1)
        form.pack(fill="x", padx=25, pady=5)

        # 日期显示
        date_text = f"{self.default_date.year}年{self.default_date.month}月{self.default_date.day}日"
        tk.Label(
            form, text=f"📅 {date_text}", font=("WenQuanYi Micro Hei", 11),
            fg=self.C["text_secondary"], bg=self.C["glass_bg"]
        ).pack(anchor="w", padx=15, pady=(12, 5))

        # 标题输入
        tk.Label(
            form, text="📝 计划标题", font=("WenQuanYi Micro Hei", 10, "bold"),
            fg=self.C["text_primary"], bg=self.C["glass_bg"]
        ).pack(anchor="w", padx=15, pady=(8, 3))

        self.title_entry = tk.Entry(
            form, font=("WenQuanYi Micro Hei", 12),
            fg=self.C["text_primary"], bg=self.C["bg_medium"],
            insertbackground=self.C["text_primary"],
            relief="flat", bd=5
        )
        self.title_entry.pack(fill="x", padx=15, pady=(0, 8))
        self.title_entry.focus_set()

        # 时间输入
        tk.Label(
            form, text="🕐 时间 (如 14:30)", font=("WenQuanYi Micro Hei", 10, "bold"),
            fg=self.C["text_primary"], bg=self.C["glass_bg"]
        ).pack(anchor="w", padx=15, pady=(5, 3))

        self.time_entry = tk.Entry(
            form, font=("WenQuanYi Micro Hei", 12),
            fg=self.C["text_primary"], bg=self.C["bg_medium"],
            insertbackground=self.C["text_primary"],
            relief="flat", bd=5
        )
        self.time_entry.pack(fill="x", padx=15, pady=(0, 8))

        # 分类选择
        tk.Label(
            form, text="🏷️ 分类", font=("WenQuanYi Micro Hei", 10, "bold"),
            fg=self.C["text_primary"], bg=self.C["glass_bg"]
        ).pack(anchor="w", padx=15, pady=(5, 3))

        self.cat_var = tk.StringVar(value=self.categories[0])
        cat_menu = tk.OptionMenu(form, self.cat_var, *self.categories)
        cat_menu.configure(
            font=("WenQuanYi Micro Hei", 11),
            fg=self.C["text_primary"], bg=self.C["bg_medium"],
            activebackground=self.C["accent1"], activeforeground="#fff",
            relief="flat", bd=0, highlightthickness=0
        )
        cat_menu.pack(fill="x", padx=15, pady=(0, 8))

        # 备注
        tk.Label(
            form, text="📌 备注 (可选)", font=("WenQuanYi Micro Hei", 10, "bold"),
            fg=self.C["text_primary"], bg=self.C["glass_bg"]
        ).pack(anchor="w", padx=15, pady=(5, 3))

        self.note_entry = tk.Entry(
            form, font=("WenQuanYi Micro Hei", 11),
            fg=self.C["text_primary"], bg=self.C["bg_medium"],
            insertbackground=self.C["text_primary"],
            relief="flat", bd=5
        )
        self.note_entry.pack(fill="x", padx=15, pady=(0, 12))

        # 按钮行
        btn_frame = tk.Frame(self.dialog, bg=self.C["bg_dark"])
        btn_frame.pack(fill="x", padx=25, pady=(15, 20))

        tk.Button(
            btn_frame, text="取消", font=("WenQuanYi Micro Hei", 11),
            fg=self.C["text_secondary"], bg=self.C["glass_bg"],
            activebackground=self.C["glass_border"], relief="flat", bd=0,
            padx=20, pady=6, cursor="hand2", command=self.dialog.destroy
        ).pack(side="right", padx=(8, 0))

        tk.Button(
            btn_frame, text="✅ 确认添加", font=("WenQuanYi Micro Hei", 11, "bold"),
            fg=self.C["bg_dark"], bg=self.C["accent3"],
            activebackground=self.C["accent2"], relief="flat", bd=0,
            padx=20, pady=6, cursor="hand2", command=self._on_confirm
        ).pack(side="right")

        # 回车确认
        self.dialog.bind("<Return>", lambda e: self._on_confirm())
        self.dialog.bind("<Escape>", lambda e: self.dialog.destroy())

    def _on_confirm(self):
        title = self.title_entry.get().strip()
        if not title:
            self.title_entry.configure(bg=self.C["danger"])
            self.title_entry.after(300, lambda: self.title_entry.configure(bg=self.C["bg_medium"]))
            self.title_entry.focus_set()
            return

        cat = self.cat_var.get()
        color_idx = 0
        if cat in self.categories:
            color_idx = self.categories.index(cat) % 6

        self.result = {
            "year": self.default_date.year,
            "month": self.default_date.month,
            "day": self.default_date.day,
            "title": title,
            "time": self.time_entry.get().strip(),
            "category": cat,
            "color_idx": color_idx,
            "note": self.note_entry.get().strip()
        }
        self.dialog.destroy()

    def show(self):
        self.parent.wait_window(self.dialog)
        return self.result


# ══════════════════════════════════════════════════════════════════
# 🚀 启动
# ══════════════════════════════════════════════════════════════════
if __name__ == "__main__":
    root = tk.Tk()
    app = NebulaCalendarApp(root)
    root.mainloop()
