import tkinter as tk
from tkinter import ttk, messagebox
import json
import os
from datetime import datetime, date

DATA_FILE = "birthdays.json"


class BirthdayReminder:
    def __init__(self, root):
        self.root = root
        self.root.title("🎂 生日提醒器")
        self.root.geometry("700x520")
        self.root.resizable(False, False)

        self.birthdays = []
        self.load_data()

        self.create_widgets()
        self.refresh_list()

    # ---------- 界面 ----------
    def create_widgets(self):
        # 顶部：标题
        title = tk.Label(self.root, text="🎂 生日提醒器",
                         font=("Microsoft YaHei", 18, "bold"), fg="#e91e63")
        title.pack(pady=10)

        # 输入区
        input_frame = tk.Frame(self.root)
        input_frame.pack(pady=5)

        tk.Label(input_frame, text="姓名:", font=("Microsoft YaHei", 11)).grid(row=0, column=0, padx=5)
        self.name_entry = tk.Entry(input_frame, width=14, font=("Microsoft YaHei", 11))
        self.name_entry.grid(row=0, column=1, padx=5)

        tk.Label(input_frame, text="生日(YYYY-MM-DD):", font=("Microsoft YaHei", 11)).grid(row=0, column=2, padx=5)
        self.date_entry = tk.Entry(input_frame, width=14, font=("Microsoft YaHei", 11))
        self.date_entry.grid(row=0, column=3, padx=5)

        add_btn = tk.Button(input_frame, text="➕ 添加", command=self.add_birthday,
                            bg="#4CAF50", fg="white", font=("Microsoft YaHei", 10, "bold"),
                            width=8, relief="flat")
        add_btn.grid(row=0, column=4, padx=8)

        # 列表区
        list_frame = tk.Frame(self.root)
        list_frame.pack(fill="both", expand=True, padx=20, pady=10)

        columns = ("name", "birthday", "age", "days_left", "next_date")
        self.tree = ttk.Treeview(list_frame, columns=columns, show="headings", height=10)

        headers = {
            "name": ("姓名", 120),
            "birthday": ("生日", 110),
            "age": ("当前年龄", 90),
            "days_left": ("距下次生日", 110),
            "next_date": ("下次生日日期", 130),
        }
        for col, (text, width) in headers.items():
            self.tree.heading(col, text=text)
            self.tree.column(col, width=width, anchor="center")

        scrollbar = ttk.Scrollbar(list_frame, orient="vertical", command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)
        self.tree.pack(side="left", fill="both", expand=True)
        scrollbar.pack(side="right", fill="y")

        # 给即将到来的生日上色
        self.tree.tag_configure("today", background="#ffcdd2", foreground="#b71c1c")
        self.tree.tag_configure("soon", background="#fff9c4")

        # 按钮区
        btn_frame = tk.Frame(self.root)
        btn_frame.pack(pady=10)

        del_btn = tk.Button(btn_frame, text="🗑 删除选中", command=self.delete_selected,
                            bg="#f44336", fg="white", font=("Microsoft YaHei", 10, "bold"),
                            width=12, relief="flat")
        del_btn.grid(row=0, column=0, padx=8)

        refresh_btn = tk.Button(btn_frame, text="🔄 刷新", command=self.refresh_list,
                                bg="#2196F3", fg="white", font=("Microsoft YaHei", 10, "bold"),
                                width=12, relief="flat")
        refresh_btn.grid(row=0, column=1, padx=8)

        check_btn = tk.Button(btn_frame, text="🔔 检查提醒", command=self.check_today,
                              bg="#FF9800", fg="white", font=("Microsoft YaHei", 10, "bold"),
                              width=12, relief="flat")
        check_btn.grid(row=0, column=2, padx=8)

        # 绑定回车添加
        self.name_entry.bind("<Return>", lambda e: self.add_birthday())
        self.date_entry.bind("<Return>", lambda e: self.add_birthday())

    # ---------- 数据 ----------
    def load_data(self):
        if os.path.exists(DATA_FILE):
            try:
                with open(DATA_FILE, "r", encoding="utf-8") as f:
                    self.birthdays = json.load(f)
            except Exception:
                self.birthdays = []

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

    # ---------- 计算 ----------
    @staticmethod
    def calc_info(birthday_str):
        """返回 (年龄, 距下次生日天数, 下次生日日期, 是否今天)"""
        bdate = datetime.strptime(birthday_str, "%Y-%m-%d").date()
        today = date.today()

        # 年龄
        age = today.year - bdate.year - ((today.month, today.day) < (bdate.month, bdate.day))

        # 下次生日
        try:
            next_bday = bdate.replace(year=today.year)
        except ValueError:  # 2月29日处理
            next_bday = date(today.year, 3, 1)
        if next_bday < today:
            try:
                next_bday = bdate.replace(year=today.year + 1)
            except ValueError:
                next_bday = date(today.year + 1, 3, 1)

        days_left = (next_bday - today).days
        is_today = (today.month == bdate.month and today.day == bdate.day)
        return age, days_left, next_bday, is_today

    # ---------- 操作 ----------
    def add_birthday(self):
        name = self.name_entry.get().strip()
        date_str = self.date_entry.get().strip()

        if not name or not date_str:
            messagebox.showwarning("提示", "请填写姓名和生日！")
            return

        try:
            datetime.strptime(date_str, "%Y-%m-%d")
        except ValueError:
            messagebox.showerror("错误", "日期格式不正确，请用 YYYY-MM-DD（如 1990-05-20）")
            return

        self.birthdays.append({"name": name, "birthday": date_str})
        self.save_data()
        self.name_entry.delete(0, tk.END)
        self.date_entry.delete(0, tk.END)
        self.refresh_list()

    def delete_selected(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showinfo("提示", "请先在列表中选择要删除的条目")
            return

        if not messagebox.askyesno("确认", "确定要删除选中的生日记录吗？"):
            return

        # 用列表重建的方式删除（避免索引错乱）
        # 通过选中行的完整信息匹配
        items_to_delete = []
        for item in selected:
            values = self.tree.item(item, "values")
            items_to_delete.append((values[0], values[1]))

        self.birthdays = [b for b in self.birthdays
                          if (b["name"], b["birthday"]) not in items_to_delete]
        self.save_data()
        self.refresh_list()

    def refresh_list(self):
        for row in self.tree.get_children():
            self.tree.delete(row)

        if not self.birthdays:
            return

        # 计算并排序
        rows = []
        for b in self.birthdays:
            try:
                age, days_left, next_bday, is_today = self.calc_info(b["birthday"])
                rows.append((b["name"], b["birthday"], age, days_left, next_bday, is_today))
            except Exception:
                continue

        rows.sort(key=lambda r: r[3])  # 按距下次生日的天数排序

        for name, bday, age, days_left, next_bday, is_today in rows:
            if is_today:
                tag = ("today",)
                days_text = "🎉 就是今天！"
            elif days_left <= 7:
                tag = ("soon",)
                days_text = f"{days_left} 天"
            else:
                tag = ()
                days_text = f"{days_left} 天"

            self.tree.insert("", tk.END,
                             values=(name, bday, f"{age} 岁", days_text, next_bday),
                             tags=tag)

    def check_today(self):
        if not self.birthdays:
            messagebox.showinfo("提醒", "还没有任何生日记录哦~")
            return

        today_list = []
        soon_list = []
        for b in self.birthdays:
            try:
                _, days_left, _, is_today = self.calc_info(b["birthday"])
            except Exception:
                continue
            if is_today:
                today_list.append(b["name"])
            elif 0 < days_left <= 7:
                soon_list.append(f"{b['name']}（{days_left}天后）")

        msg = ""
        if today_list:
            msg += "🎉 今天是以下朋友的生日：\n" + "、".join(today_list) + "\n\n"
        if soon_list:
            msg += "⏰ 未来 7 天内的生日：\n" + "\n".join(soon_list) + "\n\n"
        if not msg:
            msg = "近期没有朋友过生日~"
        messagebox.showinfo("生日提醒", msg)


if __name__ == "__main__":
    root = tk.Tk()
    app = BirthdayReminder(root)
    # 启动时自动检查一次
    root.after(500, app.check_today)
    root.mainloop()