"""
日历提醒与计划表 - 完整版
"""

import tkinter as tk
from tkinter import ttk, messagebox
import datetime
import json
import os
import threading
import time
import calendar

# ==================== 数据管理 ====================
class DataManager:
    def __init__(self, filename="schedule.json"):
        self.filename = filename
        self.data = self.load()
    
    def load(self):
        if os.path.exists(self.filename):
            with open(self.filename, "r", encoding="utf-8") as f:
                data = json.load(f)
                if "notes" not in data:
                    data["notes"] = []
                return data
        return {"events": [], "notes": []}
    
    def save(self):
        with open(self.filename, "w", encoding="utf-8") as f:
            json.dump(self.data, f, ensure_ascii=False, indent=2)
    
    def add_event(self, date, title, time_str="", note="", remind=0):
        event = {
            "date": date,
            "title": title,
            "time": time_str,
            "note": note,
            "remind": remind,
            "done": False,
            "notified": False
        }
        self.data["events"].append(event)
        self.save()
    
    def delete_event(self, index):
        if 0 <= index < len(self.data["events"]):
            del self.data["events"][index]
            self.save()
    
    def toggle_done(self, index):
        if 0 <= index < len(self.data["events"]):
            self.data["events"][index]["done"] = not self.data["events"][index]["done"]
            self.save()
    
    def get_events_by_date(self, date):
        return [e for e in self.data["events"] if e["date"] == date]
    
    def add_note(self, content):
        note = {
            "content": content,
            "date": datetime.datetime.now().strftime("%Y-%m-%d"),
            "time": datetime.datetime.now().strftime("%H:%M")
        }
        self.data["notes"].append(note)
        self.save()
    
    def delete_note(self, index):
        if 0 <= index < len(self.data["notes"]):
            del self.data["notes"][index]
            self.save()
    
    def get_all_notes(self):
        return self.data["notes"]

# ==================== 提醒系统 ====================
class Reminder:
    def __init__(self, data, callback):
        self.data = data
        self.callback = callback
        self.running = True
        t = threading.Thread(target=self.check, daemon=True)
        t.start()
    
    def check(self):
        while self.running:
            now = datetime.datetime.now()
            today = now.strftime("%Y-%m-%d")
            for e in self.data.data["events"]:
                if e["date"] == today and not e.get("notified") and e["remind"] > 0 and e["time"]:
                    try:
                        h, m = map(int, e["time"].split(":"))
                        et = now.replace(hour=h, minute=m, second=0)
                        diff = (et - now).total_seconds() / 60
                        if 0 <= diff <= e["remind"]:
                            self.callback(e)
                            e["notified"] = True
                            self.data.save()
                    except:
                        pass
            time.sleep(30)
    
    def stop(self):
        self.running = False

# ==================== 添加事件窗口 ====================
class AddWindow:
    def __init__(self, parent, date, callback):
        self.win = tk.Toplevel(parent)
        self.win.title("添加事件")
        self.win.geometry("450x480")
        self.win.configure(bg="white")
        self.win.resizable(False, False)
        self.win.transient(parent)
        self.win.grab_set()
        
        self.date = date
        self.callback = callback
        self.setup()
    
    def setup(self):
        tk.Label(self.win, text="📅 添加新事件", font=("微软雅黑", 14, "bold"),
                bg="#4a90d9", fg="white", pady=12).pack(fill=tk.X)
        
        f = tk.Frame(self.win, bg="white", padx=25, pady=15)
        f.pack(fill=tk.BOTH, expand=True)
        
        tk.Label(f, text=f"日期: {self.date}", font=("微软雅黑", 11),
                bg="#e8f4fd", fg="#4a90d9", anchor="w", padx=10, pady=5).pack(fill=tk.X, pady=(0, 12))
        
        tk.Label(f, text="事件标题 *", font=("微软雅黑", 10, "bold"), bg="white").pack(anchor="w")
        self.title_entry = tk.Entry(f, font=("微软雅黑", 11), relief="solid", borderwidth=1)
        self.title_entry.pack(fill=tk.X, ipady=5, pady=(3, 12))
        self.title_entry.focus()
        
        tf = tk.Frame(f, bg="white")
        tf.pack(fill=tk.X, pady=(0, 12))
        tk.Label(tf, text="时间 (可选)", font=("微软雅黑", 10, "bold"), bg="white").pack(anchor="w")
        
        tf2 = tk.Frame(tf, bg="white")
        tf2.pack(anchor="w", pady=3)
        
        self.hour = tk.StringVar(value="09")
        self.minute = tk.StringVar(value="00")
        
        hours = [f"{i:02d}" for i in range(24)]
        mins = [f"{i:02d}" for i in range(0, 60, 5)]
        
        ttk.Combobox(tf2, textvariable=self.hour, values=hours, width=4,
                     font=("微软雅黑", 11), state="readonly").pack(side=tk.LEFT)
        tk.Label(tf2, text=":", font=("微软雅黑", 14), bg="white").pack(side=tk.LEFT, padx=2)
        ttk.Combobox(tf2, textvariable=self.minute, values=mins, width=4,
                     font=("微软雅黑", 11), state="readonly").pack(side=tk.LEFT)
        
        tk.Label(f, text="提前提醒", font=("微软雅黑", 10, "bold"), bg="white").pack(anchor="w")
        rf = tk.Frame(f, bg="white")
        rf.pack(anchor="w", pady=3)
        
        self.remind = tk.IntVar(value=0)
        opts = [("不提醒", 0), ("5分钟", 5), ("10分钟", 10), 
                ("15分钟", 15), ("30分钟", 30), ("1小时", 60)]
        for txt, val in opts:
            tk.Radiobutton(rf, text=txt, variable=self.remind, value=val,
                          bg="white", font=("微软雅黑", 9)).pack(side=tk.LEFT, padx=(0, 8))
        
        tk.Label(f, text="备注 (可选)", font=("微软雅黑", 10, "bold"), bg="white").pack(anchor="w", pady=(12, 3))
        self.note = tk.Text(f, height=3, font=("微软雅黑", 10), relief="solid", borderwidth=1)
        self.note.pack(fill=tk.X)
        
        bf = tk.Frame(f, bg="white")
        bf.pack(fill=tk.X, pady=(15, 0))
        
        tk.Button(bf, text="取消", command=self.win.destroy,
                 bg="#e0e0e0", font=("微软雅黑", 10), padx=20, pady=5,
                 relief="flat").pack(side=tk.RIGHT, padx=(8, 0))
        tk.Button(bf, text="保存", command=self.save,
                 bg="#4a90d9", fg="white", font=("微软雅黑", 10, "bold"),
                 padx=20, pady=5, relief="flat").pack(side=tk.RIGHT)
    
    def save(self):
        title = self.title_entry.get().strip()
        if not title:
            messagebox.showwarning("提示", "请输入事件标题", parent=self.win)
            return
        time_str = f"{self.hour.get()}:{self.minute.get()}"
        note = self.note.get("1.0", tk.END).strip()
        remind = self.remind.get()
        self.callback(self.date, title, time_str, note, remind)
        self.win.destroy()

# ==================== 添加笔记窗口 ====================
class NoteWindow:
    def __init__(self, parent, callback):
        self.win = tk.Toplevel(parent)
        self.win.title("添加笔记")
        self.win.geometry("420x380")
        self.win.configure(bg="white")
        self.win.resizable(False, False)
        self.win.transient(parent)
        self.win.grab_set()
        
        self.callback = callback
        self.setup()
    
    def setup(self):
        tk.Label(self.win, text="📝 添加笔记", font=("微软雅黑", 14, "bold"),
                bg="#f0ad4e", fg="white", pady=12).pack(fill=tk.X)
        
        f = tk.Frame(self.win, bg="white", padx=20, pady=15)
        f.pack(fill=tk.BOTH, expand=True)
        
        tk.Label(f, text="笔记内容:", font=("微软雅黑", 10, "bold"), bg="white").pack(anchor="w")
        
        self.text = tk.Text(f, height=8, font=("微软雅黑", 11), 
                           relief="solid", borderwidth=1)
        self.text.pack(fill=tk.BOTH, expand=True, pady=(5, 15))
        self.text.focus()
        
        bf = tk.Frame(f, bg="white")
        bf.pack(fill=tk.X)
        
        tk.Button(bf, text="取消", command=self.win.destroy,
                 bg="#e0e0e0", font=("微软雅黑", 10), padx=20, pady=5,
                 relief="flat").pack(side=tk.RIGHT, padx=(8, 0))
        tk.Button(bf, text="保存笔记", command=self.save,
                 bg="#f0ad4e", fg="white", font=("微软雅黑", 10, "bold"),
                 padx=20, pady=5, relief="flat").pack(side=tk.RIGHT)
    
    def save(self):
        content = self.text.get("1.0", tk.END).strip()
        if not content:
            messagebox.showwarning("提示", "请输入笔记内容", parent=self.win)
            return
        self.callback(content)
        self.win.destroy()

# ==================== 主程序 ====================
class App:
    def __init__(self):
        self.root = tk.Tk()
        self.root.title("日历提醒与计划表")
        self.root.geometry("1000x680")
        self.root.configure(bg="#f0f0f0")
        self.root.minsize(800, 550)
        
        self.data = DataManager()
        self.today = datetime.date.today()
        self.view_year = self.today.year
        self.view_month = self.today.month
        self.sel_date = self.today
        self.show_notes = False
        
        self.reminder = Reminder(self.data, self.show_alert)
        self.build()
        self.refresh()
    
    def build(self):
        main = tk.Frame(self.root, bg="#f0f0f0")
        main.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
        
        left = tk.Frame(main, bg="white", relief="solid", borderwidth=1)
        left.pack(side=tk.LEFT, fill=tk.Y)
        
        self.month_label = tk.Label(left, text="", font=("微软雅黑", 15, "bold"),
                                    bg="#4a90d9", fg="white", pady=10)
        self.month_label.pack(fill=tk.X)
        
        nav = tk.Frame(left, bg="white")
        nav.pack(fill=tk.X, pady=5)
        tk.Button(nav, text="◀", command=self.prev_month,
                 bg="#e8e8e8", relief="flat", width=3).pack(side=tk.LEFT, padx=5)
        tk.Button(nav, text="今天", command=self.go_today,
                 bg="#4a90d9", fg="white", relief="flat", padx=10).pack(side=tk.LEFT, padx=5)
        tk.Button(nav, text="▶", command=self.next_month,
                 bg="#e8e8e8", relief="flat", width=3).pack(side=tk.LEFT, padx=5)
        
        wk = tk.Frame(left, bg="white")
        wk.pack(fill=tk.X, padx=5)
        for i, d in enumerate(["一","二","三","四","五","六","日"]):
            c = "#ff6b6b" if i >= 5 else "#333"
            tk.Label(wk, text=d, width=4, font=("微软雅黑", 9, "bold"),
                    bg="#f5f5f5", fg=c).pack(side=tk.LEFT, padx=1, pady=2)
        
        self.cal = tk.Frame(left, bg="white")
        self.cal.pack(fill=tk.BOTH, padx=5, pady=5)
        
        right = tk.Frame(main, bg="white", relief="solid", borderwidth=1)
        right.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)
        
        hdr = tk.Frame(right, bg="white")
        hdr.pack(fill=tk.X, padx=20, pady=(15, 5))
        
        self.date_label = tk.Label(hdr, text="", font=("微软雅黑", 15, "bold"), bg="white")
        self.date_label.pack(side=tk.LEFT)
        
        self.count_label = tk.Label(hdr, text="", font=("微软雅黑", 10), bg="white", fg="#999")
        self.count_label.pack(side=tk.RIGHT)
        
        tk.Frame(right, bg="#eee", height=1).pack(fill=tk.X, padx=20)
        
        btn_bar = tk.Frame(right, bg="white")
        btn_bar.pack(fill=tk.X, padx=20, pady=(10, 5))
        
        self.title_label = tk.Label(btn_bar, text="日程安排", font=("微软雅黑", 11, "bold"), bg="white")
        self.title_label.pack(side=tk.LEFT)
        
        self.note_btn = tk.Button(btn_bar, text="📝 添加笔记", command=self.open_note,
                                 bg="#f0ad4e", fg="white", font=("微软雅黑", 9, "bold"),
                                 relief="flat", padx=10)
        self.note_btn.pack(side=tk.RIGHT, padx=(5, 0))
        
        self.view_btn = tk.Button(btn_bar, text="📝 笔记列表", command=self.toggle_view,
                                 bg="#e8e8e8", font=("微软雅黑", 9, "bold"),
                                 relief="flat", padx=10)
        self.view_btn.pack(side=tk.RIGHT, padx=(5, 0))
        
        tk.Button(btn_bar, text="+ 添加事件", command=self.open_add,
                 bg="#4a90d9", fg="white", font=("微软雅黑", 9, "bold"),
                 relief="flat", padx=10).pack(side=tk.RIGHT, padx=(5, 0))
        
        container = tk.Frame(right, bg="white")
        container.pack(fill=tk.BOTH, expand=True, padx=20, pady=(5, 15))
        
        canvas = tk.Canvas(container, bg="white", highlightthickness=0)
        scroll = tk.Scrollbar(container, orient="vertical", command=canvas.yview)
        self.list_frame = tk.Frame(canvas, bg="white")
        
        self.list_frame.bind("<Configure>", lambda e: canvas.configure(scrollregion=canvas.bbox("all")))
        canvas.create_window((0, 0), window=self.list_frame, anchor="nw")
        canvas.configure(yscrollcommand=scroll.set)
        
        canvas.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scroll.pack(side=tk.RIGHT, fill=tk.Y)
        
        status = tk.Frame(self.root, bg="#e8e8e8", height=30)
        status.pack(fill=tk.X, side=tk.BOTTOM)
        self.status = tk.Label(status, text="就绪", bg="#e8e8e8", font=("微软雅黑", 9), anchor="w")
        self.status.pack(fill=tk.X, padx=15, pady=3)
    
    def toggle_view(self):
        self.show_notes = not self.show_notes
        if self.show_notes:
            self.view_btn.config(text="📅 日程视图", bg="#4a90d9", fg="white")
            self.title_label.config(text="📝 全部笔记")
        else:
            self.view_btn.config(text="📝 笔记列表", bg="#e8e8e8", fg="black")
            self.title_label.config(text="日程安排")
        self.refresh()
    
    def draw_calendar(self):
        for w in self.cal.winfo_children():
            w.destroy()
        
        self.month_label.config(text=f"{self.view_year}年 {self.view_month}月")
        
        days = calendar.monthrange(self.view_year, self.view_month)[1]
        first = datetime.date(self.view_year, self.view_month, 1).weekday()
        
        event_dates = set()
        for e in self.data.data["events"]:
            event_dates.add(e["date"])
        
        day = 1
        total = first + days
        rows = (total + 6) // 7
        
        for r in range(rows):
            rf = tk.Frame(self.cal, bg="white")
            rf.pack(fill=tk.X)
            
            for c in range(7):
                idx = r * 7 + c
                
                if idx < first or day > days:
                    tk.Label(rf, text="", width=4, height=2,
                            bg="#fafafa").pack(side=tk.LEFT, padx=1, pady=1)
                else:
                    date_str = f"{self.view_year}-{self.view_month:02d}-{day:02d}"
                    
                    is_today = (self.view_year == self.today.year and
                               self.view_month == self.today.month and
                               day == self.today.day)
                    is_sel = (self.sel_date.year == self.view_year and
                             self.sel_date.month == self.view_month and
                             self.sel_date.day == day)
                    
                    if is_sel:
                        bg = "#4a90d9"
                        fg = "white"
                    elif is_today:
                        bg = "#fff3cd"
                        fg = "#856404"
                    else:
                        bg = "white"
                        fg = "#333"
                    
                    if c >= 5 and not is_sel:
                        fg = "#ff6b6b"
                    
                    cell = tk.Frame(rf, bg=bg, width=48, height=48)
                    cell.pack_propagate(False)
                    cell.pack(side=tk.LEFT, padx=1, pady=1)
                    
                    lbl = tk.Label(cell, text=str(day), bg=bg, fg=fg,
                                  font=("微软雅黑", 10, "bold"))
                    lbl.pack(anchor="ne", padx=3, pady=2)
                    
                    if date_str in event_dates:
                        tk.Label(cell, text="●", bg=bg, fg="#4a90d9",
                                font=("微软雅黑", 7)).pack(anchor="sw", padx=3)
                    
                    def click(d=date_str):
                        return lambda e: self.select_date(d)
                    
                    cell.bind("<Button-1>", click(date_str))
                    lbl.bind("<Button-1>", click(date_str))
                    
                    day += 1
    
    def select_date(self, date_str):
        y, m, d = map(int, date_str.split("-"))
        self.sel_date = datetime.date(y, m, d)
        if self.show_notes:
            self.show_notes = False
            self.view_btn.config(text="📝 笔记列表", bg="#e8e8e8", fg="black")
            self.title_label.config(text="日程安排")
        self.refresh()
    
    def refresh(self):
        self.draw_calendar()
        self.show_content()
        
        if not self.show_notes:
            weekdays = ["星期一","星期二","星期三","星期四","星期五","星期六","星期日"]
            wd = weekdays[self.sel_date.weekday()]
            self.date_label.config(text=f"{self.sel_date.year}年{self.sel_date.month}月{self.sel_date.day}日 {wd}")
            
            ds = self.sel_date.strftime("%Y-%m-%d")
            evs = self.data.get_events_by_date(ds)
            done = sum(1 for e in evs if e.get("done"))
            self.count_label.config(text=f"共{len(evs)}项 已完成{done}项")
        else:
            self.date_label.config(text="📝 全部笔记")
            notes = self.data.get_all_notes()
            self.count_label.config(text=f"共{len(notes)}条笔记")
    
    def show_content(self):
        for w in self.list_frame.winfo_children():
            w.destroy()
        
        if self.show_notes:
            self.show_notes_list()
        else:
            self.show_events_list()
    
    def show_events_list(self):
        ds = self.sel_date.strftime("%Y-%m-%d")
        evs = self.data.get_events_by_date(ds)
        
        if not evs:
            ef = tk.Frame(self.list_frame, bg="#f9f9f9", height=150)
            ef.pack(fill=tk.BOTH, expand=True)
            ef.pack_propagate(False)
            tk.Label(ef, text="暂无安排", font=("微软雅黑", 13),
                    bg="#f9f9f9", fg="#ccc").pack(expand=True)
            tk.Label(ef, text="点击右上角「添加事件」创建日程",
                    font=("微软雅黑", 9), bg="#f9f9f9", fg="#ddd").pack()
            return
        
        for i, e in enumerate(evs):
            card = tk.Frame(self.list_frame, bg="#f8f9fa", relief="solid",
                           borderwidth=1, padx=12, pady=10)
            card.pack(fill=tk.X, pady=3)
            
            r1 = tk.Frame(card, bg="#f8f9fa")
            r1.pack(fill=tk.X)
            
            done = tk.BooleanVar(value=e.get("done"))
            tk.Checkbutton(r1, variable=done, command=lambda idx=i: self.toggle(idx),
                          bg="#f8f9fa").pack(side=tk.LEFT)
            
            title = e["title"]
            if e.get("done"):
                title = "✓ " + title
            ft = ("微软雅黑", 11, "overstrike" if e.get("done") else "bold")
            tk.Label(r1, text=title, font=ft, bg="#f8f9fa").pack(side=tk.LEFT, fill=tk.X, expand=True)
            
            tk.Button(r1, text="✕", command=lambda idx=i: self.delete(idx),
                     bg="#ff6b6b", fg="white", font=("微软雅黑", 8),
                     width=2, relief="flat").pack(side=tk.RIGHT)
            
            r2 = tk.Frame(card, bg="#f8f9fa")
            r2.pack(fill=tk.X, pady=(5, 0))
            
            if e["time"]:
                tk.Label(r2, text=f"🕐 {e['time']}", font=("微软雅黑", 9),
                        fg="#666", bg="#f8f9fa").pack(side=tk.LEFT, padx=(22, 10))
            
            if e["remind"] > 0:
                tk.Label(r2, text=f"🔔 提前{e['remind']}分钟", font=("微软雅黑", 9),
                        fg="#f0ad4e", bg="#f8f9fa").pack(side=tk.LEFT)
            
            if e["note"]:
                r3 = tk.Frame(card, bg="#f8f9fa")
                r3.pack(fill=tk.X, pady=(5, 0))
                tk.Label(r3, text=f"📝 {e['note']}", font=("微软雅黑", 9),
                        fg="#888", bg="#f8f9fa", wraplength=400).pack(padx=(22, 0))
    
    def show_notes_list(self):
        notes = self.data.get_all_notes()
        
        if not notes:
            ef = tk.Frame(self.list_frame, bg="#f9f9f9", height=150)
            ef.pack(fill=tk.BOTH, expand=True)
            ef.pack_propagate(False)
            tk.Label(ef, text="暂无笔记", font=("微软雅黑", 13),
                    bg="#f9f9f9", fg="#ccc").pack(expand=True)
            tk.Label(ef, text="点击上方「添加笔记」创建笔记",
                    font=("微软雅黑", 9), bg="#f9f9f9", fg="#ddd").pack()
            return
        
        display_notes = list(reversed(notes))
        
        for i, note in enumerate(display_notes):
            card = tk.Frame(self.list_frame, bg="#fffdf5", relief="solid",
                           borderwidth=1, padx=12, pady=10)
            card.pack(fill=tk.X, pady=3)
            
            r1 = tk.Frame(card, bg="#fffdf5")
            r1.pack(fill=tk.X)
            
            tk.Label(r1, text="📝", font=("微软雅黑", 12), bg="#fffdf5").pack(side=tk.LEFT, padx=(0, 8))
            tk.Label(r1, text=note["content"], font=("微软雅黑", 11),
                    bg="#fffdf5", anchor="w", wraplength=500, justify="left").pack(side=tk.LEFT, fill=tk.X, expand=True)
            
            original_idx = len(notes) - 1 - i
            tk.Button(r1, text="✕", command=lambda idx=original_idx: self.delete_note(idx),
                     bg="#ff6b6b", fg="white", font=("微软雅黑", 8),
                     width=2, relief="flat").pack(side=tk.RIGHT)
            
            r2 = tk.Frame(card, bg="#fffdf5")
            r2.pack(fill=tk.X, pady=(5, 0))
            tk.Label(r2, text=f"{note['date']} {note['time']}", font=("微软雅黑", 8),
                    fg="#bbb", bg="#fffdf5").pack(padx=(22, 0))
    
    def open_add(self):
        ds = self.sel_date.strftime("%Y-%m-%d")
        AddWindow(self.root, ds, self.add_event)
    
    def open_note(self):
        NoteWindow(self.root, self.add_note)
    
    def add_event(self, date, title, time_str, note, remind):
        self.data.add_event(date, title, time_str, note, remind)
        self.refresh()
        self.status.config(text=f"已添加: {title}")
    
    def add_note(self, content):
        self.data.add_note(content)
        self.refresh()
        self.status.config(text="笔记已保存")
    
    def toggle(self, idx):
        self.data.toggle_done(idx)
        self.refresh()
    
    def delete(self, idx):
        if messagebox.askyesno("确认", "确定删除此事件？"):
            self.data.delete_event(idx)
            self.refresh()
            self.status.config(text="事件已删除")
    
    def delete_note(self, idx):
        if messagebox.askyesno("确认", "确定删除此笔记？"):
            self.data.delete_note(idx)
            self.refresh()
            self.status.config(text="笔记已删除")
    
    def prev_month(self):
        if self.view_month == 1:
            self.view_month = 12
            self.view_year -= 1
        else:
            self.view_month -= 1
        self.refresh()
    
    def next_month(self):
        if self.view_month == 12:
            self.view_month = 1
            self.view_year += 1
        else:
            self.view_month += 1
        self.refresh()
    
    def go_today(self):
        self.view_year = self.today.year
        self.view_month = self.today.month
        self.sel_date = self.today
        self.show_notes = False
        self.view_btn.config(text="📝 笔记列表", bg="#e8e8e8", fg="black")
        self.title_label.config(text="日程安排")
        self.refresh()
    
    def show_alert(self, event):
        self.status.config(text=f"🔔 提醒: {event['title']}")
        messagebox.showinfo("提醒", f"事件: {event['title']}\n时间: {event['time']}")
    
    def run(self):
        def on_close():
            self.reminder.stop()
            self.root.destroy()
        self.root.protocol("WM_DELETE_WINDOW", on_close)
        self.root.mainloop()

# ==================== 启动 ====================
if __name__ == "__main__":
    App().run()