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

# ==================== 主题配色 ====================
THEMES = {
    "🎀 樱花粉": {
        "bg": "#FFF0F5", "panel": "#FCE4EC", "fg": "#C2185B",
        "btn": "#F48FB1", "btn_fg": "#FFFFFF", "btn_active": "#E91E63",
        "list_bg": "#FFF8FA", "list_fg": "#880E4F", "accent": "#FF80AB",
        "card": "#F8BBD0", "highlight": "#F06292"
    },
    "🦄 梦幻紫": {
        "bg": "#F3E5F5", "panel": "#E1BEE7", "fg": "#6A1B9A",
        "btn": "#CE93D8", "btn_fg": "#FFFFFF", "btn_active": "#8E24AA",
        "list_bg": "#FAF0FF", "list_fg": "#4A148C", "accent": "#EA80FC",
        "card": "#E1BEE7", "highlight": "#AB47BC"
    },
    "🐬 天空蓝": {
        "bg": "#E3F2FD", "panel": "#BBDEFB", "fg": "#0D47A1",
        "btn": "#64B5F6", "btn_fg": "#FFFFFF", "btn_active": "#1565C0",
        "list_bg": "#F0F7FF", "list_fg": "#0D47A1", "accent": "#40C4FF",
        "card": "#BBDEFB", "highlight": "#1E88E5"
    },
    "🍀 抹茶绿": {
        "bg": "#E8F5E9", "panel": "#C8E6C9", "fg": "#1B5E20",
        "btn": "#81C784", "btn_fg": "#FFFFFF", "btn_active": "#2E7D32",
        "list_bg": "#F5FFF5", "list_fg": "#1B5E20", "accent": "#69F0AE",
        "card": "#C8E6C9", "highlight": "#43A047"
    },
    "🧡 蜜桔橙": {
        "bg": "#FFF3E0", "panel": "#FFE0B2", "fg": "#BF360C",
        "btn": "#FF8A65", "btn_fg": "#FFFFFF", "btn_active": "#E64A19",
        "list_bg": "#FFF8F0", "list_fg": "#BF360C", "accent": "#FFAB40",
        "card": "#FFE0B2", "highlight": "#FF7043"
    },
    "🌈 糖果色": {
        "bg": "#FFF9C4", "panel": "#FFF59D", "fg": "#F57F17",
        "btn": "#FFD54F", "btn_fg": "#FFFFFF", "btn_active": "#F9A825",
        "list_bg": "#FFFFF0", "list_fg": "#E65100", "accent": "#FF6E40",
        "card": "#FFF59D", "highlight": "#FFB300"
    },
}

# ==================== 数据文件 ====================
DATA_FILE = "birthdays.json"

# ==================== 全局状态 ====================
current_theme = "🎀 樱花粉"
birthdays = {}  # {name: "MM-DD"}
theme_buttons = {}
tool_buttons = []


# ==================== 数据持久化 ====================
def load_data():
    global birthdays
    if os.path.exists(DATA_FILE):
        try:
            with open(DATA_FILE, "r", encoding="utf-8") as f:
                birthdays = json.load(f)
        except:
            birthdays = {}


def save_data():
    with open(DATA_FILE, "w", encoding="utf-8") as f:
        json.dump(birthdays, f, ensure_ascii=False, indent=2)


# ==================== 换肤 ====================
def apply_theme(name):
    global current_theme
    current_theme = name
    t = THEMES[name]

    root.configure(bg=t["bg"])
    for frame in [
        frame_top, frame_main, frame_left, frame_right,
        frame_upcoming, frame_all_list, frame_actions,
        frame_today, frame_theme_bar, frame_bottom
    ]:
        frame.configure(bg=t["bg"])

    # Labels
    for lbl in [
        label_title, label_subtitle,
        label_upcoming_title, label_all_title,
        label_today_title, label_today_text,
        label_footer, label_days,
    ]:
        try:
            lbl.configure(bg=t["bg"], fg=t["fg"])
        except:
            pass

    # Buttons
    for btn in tool_buttons:
        btn.configure(bg=t["btn"], fg=t["btn_fg"], activebackground=t["btn_active"])

    # Theme buttons
    for n, btn in theme_buttons.items():
        if n == name:
            btn.configure(relief="sunken", bd=3, bg=t["btn_active"], fg=t["btn_fg"])
        else:
            btn.configure(relief="raised", bd=1, bg=t["btn"], fg=t["btn_fg"])

    # Listbox
    listbox_all.configure(bg=t["list_bg"], fg=t["list_fg"], selectbackground=t["btn"])
    listbox_upcoming.configure(bg=t["list_bg"], fg=t["list_fg"], selectbackground=t["btn"])

    # Cards
    try:
        frame_today_card.configure(bg=t["card"])
        frame_upcoming_card.configure(bg=t["card"])
        frame_all_card.configure(bg=t["card"])
    except:
        pass

    refresh_all()


# ==================== 日期工具 ====================
def get_days_until(birthday_mmdd):
    """计算距离下一个生日的天数"""
    today = datetime.now()
    month, day = map(int, birthday_mmdd.split("-"))
    this_year = today.year
    next_birthday = datetime(this_year, month, day)

    if next_birthday.date() < today.date():
        next_birthday = datetime(this_year + 1, month, day)

    return (next_birthday.date() - today.date()).days


def get_age(birthday_mmdd):
    """计算周岁"""
    today = datetime.now()
    month, day = map(int, birthday_mmdd.split("-"))
    this_year = today.year
    next_birthday = datetime(this_year, month, day)

    if next_birthday.date() < today.date():
        return this_year - datetime.strptime(birthday_mmdd, "%m-%d").year + 1
    return this_year - datetime.strptime(birthday_mmdd, "%m-%d").year


def get_zodiac(mmdd):
    """根据月日判断星座"""
    m, d = map(int, mmdd.split("-"))
    zodiacs = [
        ((1, 20), (2, 18), "♒ 水瓶座"),
        ((2, 19), (3, 20), "♓ 双鱼座"),
        ((3, 21), (4, 19), "♈ 白羊座"),
        ((4, 20), (5, 20), "♉ 金牛座"),
        ((5, 21), (6, 21), "♊ 双子座"),
        ((6, 22), (7, 22), "♋ 巨蟹座"),
        ((7, 23), (8, 22), "♌ 狮子座"),
        ((8, 23), (9, 22), "♍ 处女座"),
        ((9, 23), (10, 23), "♎ 天秤座"),
        ((10, 24), (11, 21), "♏ 天蝎座"),
        ((11, 22), (12, 21), "♐ 射手座"),
        ((12, 22), (1, 19), "♑ 摩羯座"),
    ]
    for start, end, name in zodiacs:
        if (m == start[0] and d >= start[1]) or (m == end[0] and d <= end[1]):
            return name
    return "♑ 摩羯座"


# ==================== 业务逻辑 ====================
def add_birthday():
    dialog = BirthdayDialog(root, "添加生日", THEMES[current_theme])
    result = dialog.result
    if result:
        name, mmdd = result
        if name in birthdays:
            messagebox.showinfo("提示", f"「{name}」已存在，将更新生日日期～")
        birthdays[name] = mmdd
        save_data()
        refresh_all()
        messagebox.showinfo("成功", f"🎉 已添加 {name} 的生日（{mmdd}）")


def edit_birthday():
    sel = listbox_all.curselection()
    if not sel:
        messagebox.showwarning("提示", "请先选择一个小伙伴～")
        return
    name = listbox_all.get(sel[0]).split(" (")[0].strip()
    old_mmdd = birthdays.get(name, "")
    dialog = BirthdayDialog(root, "编辑生日", THEMES[current_theme], name, old_mmdd)
    result = dialog.result
    if result:
        new_name, new_mmdd = result
        if new_name != name:
            del birthdays[name]
        birthdays[new_name] = new_mmdd
        save_data()
        refresh_all()


def delete_birthday():
    sel = listbox_all.curselection()
    if not sel:
        messagebox.showwarning("提示", "请先选择一个小伙伴～")
        return
    name = listbox_all.get(sel[0]).split(" (")[0].strip()
    if messagebox.askyesno("确认删除", f"确定要删除「{name}」的生日记录吗？"):
        del birthdays[name]
        save_data()
        refresh_all()


def refresh_all():
    """刷新所有显示"""
    refresh_today()
    refresh_upcoming()
    refresh_all_list()


def refresh_today():
    """刷新今日生日"""
    today_str = datetime.now().strftime("%m-%d")
    today_names = [n for n, d in birthdays.items() if d == today_str]

    t = THEMES[current_theme]
    if today_names:
        text = "🎂 今天过生日的小伙伴 🎉\n\n"
        for n in today_names:
            zodiac = get_zodiac(birthdays[n])
            text += f"  ✨ {n} ✨  {zodiac}\n"
        label_today_text.configure(text=text, fg=t["highlight"], font=("Comic Sans MS", 14, "bold"))
    else:
        label_today_text.configure(
            text="🌼 今天没有小伙伴过生日\n\n期待下次的惊喜吧～",
            fg=t["fg"], font=("Comic Sans MS", 12)
        )


def refresh_upcoming():
    """刷新即将到来的生日"""
    listbox_upcoming.delete(0, tk.END)
    if not birthdays:
        listbox_upcoming.insert(tk.END, "  （暂无数据）")
        return

    sorted_items = sorted(birthdays.items(), key=lambda x: get_days_until(x[1]))
    for name, mmdd in sorted_items[:5]:
        days = get_days_until(mmdd)
        emoji = "🔥" if days <= 7 else "📅"
        if days == 0:
            text = f"  {emoji} {name} — 就是今天！🎉"
        elif days == 1:
            text = f"  {emoji} {name} — 明天！"
        else:
            text = f"  {emoji} {name} — 还有 {days} 天"
        listbox_upcoming.insert(tk.END, text)


def refresh_all_list():
    """刷新全部生日列表"""
    listbox_all.delete(0, tk.END)
    if not birthdays:
        listbox_all.insert(tk.END, "  （暂无数据，点击添加吧～）")
        label_days.configure(text="共有 0 位小伙伴 🌸")
        return

    sorted_items = sorted(birthdays.items(), key=lambda x: get_days_until(x[1]))
    for name, mmdd in sorted_items:
        days = get_days_until(mmdd)
        zodiac = get_zodiac(mmdd)
        listbox_all.insert(tk.END, f"  {name} ({mmdd}) {zodiac} — {days}天后")

    label_days.configure(text=f"共有 {len(birthdays)} 位小伙伴 🌸")


# ==================== 生日对话框 ====================
class BirthdayDialog:
    def __init__(self, parent, title, theme, name="", mmdd=""):
        self.result = None
        self.theme = theme

        self.dialog = tk.Toplevel(parent)
        self.dialog.title(title)
        self.dialog.geometry("360x260")
        self.dialog.resizable(False, False)
        self.dialog.configure(bg=theme["panel"])
        self.dialog.transient(parent)
        self.dialog.grab_set()

        # 居中
        self.dialog.update_idletasks()
        x = parent.winfo_rootx() + (parent.winfo_width() - 360) // 2
        y = parent.winfo_rooty() + (parent.winfo_height() - 260) // 2
        self.dialog.geometry(f"360x260+{x}+{y}")

        # 标题
        tk.Label(
            self.dialog, text=f"🎀 {title} 🎀",
            font=("Comic Sans MS", 16, "bold"),
            bg=theme["panel"], fg=theme["fg"]
        ).pack(pady=12)

        # 姓名
        f1 = tk.Frame(self.dialog, bg=theme["panel"])
        f1.pack(pady=5)
        tk.Label(f1, text="姓名：", font=("Comic Sans MS", 12),
                 bg=theme["panel"], fg=theme["fg"]).pack(side="left", padx=5)
        self.entry_name = tk.Entry(f1, font=("Comic Sans MS", 12), width=16, justify="center")
        self.entry_name.pack(side="left", padx=5)
        if name:
            self.entry_name.insert(0, name)

        # 生日
        f2 = tk.Frame(self.dialog, bg=theme["panel"])
        f2.pack(pady=5)
        tk.Label(f2, text="生日：", font=("Comic Sans MS", 12),
                 bg=theme["panel"], fg=theme["fg"]).pack(side="left", padx=5)

        self.month_var = tk.StringVar(value=mmdd[:2] if mmdd else "01")
        self.day_var = tk.StringVar(value=mmdd[3:] if mmdd else "01")

        months = [f"{i:02d}" for i in range(1, 13)]
        days = [f"{i:02d}" for i in range(1, 32)]

        tk.OptionMenu(self.dialog, self.month_var, *months).pack(pady=2)
        tk.Label(self.dialog, text="月", font=("Comic Sans MS", 10),
                 bg=theme["panel"], fg=theme["fg"]).pack()
        tk.OptionMenu(self.dialog, self.day_var, *days).pack(pady=2)
        tk.Label(self.dialog, text="日", font=("Comic Sans MS", 10),
                 bg=theme["panel"], fg=theme["fg"]).pack()

        # 按钮
        f3 = tk.Frame(self.dialog, bg=theme["panel"])
        f3.pack(pady=12)
        tk.Button(
            f3, text="✅ 确定", font=("Comic Sans MS", 11, "bold"),
            bg=theme["btn"], fg=theme["btn_fg"],
            activebackground=theme["btn_active"],
            relief="flat", padx=15, pady=3,
            command=self.on_ok
        ).pack(side="left", padx=8)
        tk.Button(
            f3, text="❌ 取消", font=("Comic Sans MS", 11),
            bg="#E0E0E0", fg="#333",
            relief="flat", padx=15, pady=3,
            command=self.on_cancel
        ).pack(side="left", padx=8)

        self.dialog.wait_window()

    def on_ok(self):
        name = self.entry_name.get().strip()
        mmdd = f"{self.month_var.get()}-{self.day_var.get()}"
        if not name:
            messagebox.showwarning("提示", "请输入姓名～", parent=self.dialog)
            return
        self.result = (name, mmdd)
        self.dialog.destroy()

    def on_cancel(self):
        self.dialog.destroy()


# ==================== 创建主窗口 ====================
root = tk.Tk()
root.title("🎂 卡通生日提醒器 🎀")
root.geometry("680x720")
root.resizable(False, False)

# ==================== 加载数据 ====================
load_data()

# ==================== 顶部：标题 + 换肤 ====================
frame_top = tk.Frame(root)
frame_top.pack(fill="x", pady=8)

label_title = tk.Label(
    frame_top, text="🎂 生日提醒器 🎀",
    font=("Comic Sans MS", 26, "bold")
)
label_title.pack()

label_subtitle = tk.Label(
    frame_top, text="✨ 记录每一个重要的日子 ✨",
    font=("Comic Sans MS", 11)
)
label_subtitle.pack(pady=2)

# 主题栏
frame_theme_bar = tk.Frame(frame_top)
frame_theme_bar.pack(pady=5)

tk.Label(
    frame_theme_bar, text="🎨 换肤：",
    font=("Comic Sans MS", 11, "bold")
).pack(side="left", padx=5)

for name in THEMES:
    t = THEMES[name]
    btn = tk.Button(
        frame_theme_bar, text=name,
        font=("Comic Sans MS", 9, "bold"),
        relief="raised", bd=1, padx=6, pady=2,
        command=lambda n=name: apply_theme(n)
    )
    btn.pack(side="left", padx=3)
    theme_buttons[name] = btn

# ==================== 主区域 ====================
frame_main = tk.Frame(root)
frame_main.pack(fill="both", expand=True, padx=12)

# ====== 左侧 ======
frame_left = tk.Frame(frame_main)
frame_left.pack(side="left", fill="both", expand=True, padx=(0, 6))

# 今日生日卡片
frame_today = tk.Frame(frame_left)
frame_today.pack(fill="x", pady=5)

label_today_title = tk.Label(
    frame_today, text="🎉 今日生日",
    font=("Comic Sans MS", 13, "bold")
)
label_today_title.pack(anchor="w")

frame_today_card = tk.Frame(frame_today, relief="solid", bd=2)
frame_today_card.pack(fill="x", pady=3)

label_today_text = tk.Label(
    frame_today_card, text="",
    font=("Comic Sans MS", 12),
    justify="center", wraplength=280,
    pady=8
)
label_today_text.pack()

# 即将到来
frame_upcoming = tk.Frame(frame_left)
frame_upcoming.pack(fill="x", pady=5)

label_upcoming_title = tk.Label(
    frame_upcoming, text="📅 即将到来（Top 5）",
    font=("Comic Sans MS", 13, "bold")
)
label_upcoming_title.pack(anchor="w")

frame_upcoming_card = tk.Frame(frame_upcoming, relief="solid", bd=2)
frame_upcoming_card.pack(fill="x", pady=3)

listbox_upcoming = tk.Listbox(
    frame_upcoming_card, font=("Comic Sans MS", 11),
    height=6, relief="flat", bd=0
)
listbox_upcoming.pack(fill="x", padx=5, pady=3)

# ====== 右侧 ======
frame_right = tk.Frame(frame_main)
frame_right.pack(side="right", fill="both", expand=True, padx=(6, 0))

# 全部列表
frame_all_list = tk.Frame(frame_right)
frame_all_list.pack(fill="both", expand=True)

label_all_title = tk.Label(
    frame_all_list, text="📋 全部生日",
    font=("Comic Sans MS", 13, "bold")
)
label_all_title.pack(anchor="w")

frame_all_card = tk.Frame(frame_all_list, relief="solid", bd=2)
frame_all_card.pack(fill="both", expand=True, pady=3)

listbox_all = tk.Listbox(
    frame_all_card, font=("Comic Sans MS", 11),
    height=12, relief="flat", bd=0
)
listbox_all.pack(fill="both", expand=True, padx=5, pady=3)

label_days = tk.Label(
    frame_all_list, text="",
    font=("Comic Sans MS", 10)
)
label_days.pack(pady=2)

# 操作按钮
frame_actions = tk.Frame(frame_right)
frame_actions.pack(fill="x", pady=8)

actions = [
    ("➕ 添加", add_birthday),
    ("✏️ 编辑", edit_birthday),
    ("🗑️ 删除", delete_birthday),
]

for text, cmd in actions:
    btn = tk.Button(
        frame_actions, text=text,
        font=("Comic Sans MS", 11, "bold"),
        relief="flat", padx=10, pady=4,
        command=cmd
    )
    btn.pack(side="left", padx=5, expand=True, fill="x")
    tool_buttons.append(btn)

# ==================== 底部 ====================
frame_bottom = tk.Frame(root)
frame_bottom.pack(side="bottom", fill="x", pady=5)

label_footer = tk.Label(
    frame_bottom,
    text="💡 数据保存在 birthdays.json 文件中，不会丢失哦～",
    font=("Comic Sans MS", 9)
)
label_footer.pack(side="bottom", pady=3)

# ==================== 初始化 ====================
apply_theme("🎀 樱花粉")

root.mainloop()
