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


class BirthdayReminder:
    DATA_FILE = "birthdays.json"

    def __init__(self, root):
        self.root = root
        self.root.title("🎂 生日提醒器")
        self.root.geometry("600x520")
        self.root.configure(bg="#f0f4f8")
        self.root.resizable(False, False)

        self.birthdays = []
        self.load_data()

        self.create_widgets()
        self.refresh_list()

        # 启动时检查今天是否有生日
        self.root.after(500, self.check_today)
        # 每 60 秒检查一次
        self.root.after(60000, self.periodic_check)

    # ==================== 数据持久化 ====================

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

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

    # ==================== 界面构建 ====================

    def create_widgets(self):
        # ====== 标题 ======
        title_frame = tk.Frame(self.root, bg="#4a90d9", height=60)
        title_frame.pack(fill="x")
        title_frame.pack_propagate(False)
        tk.Label(
            title_frame, text="🎂 生日提醒器",
            font=("微软雅黑", 18, "bold"), fg="white", bg="#4a90d9"
        ).pack(expand=True)

        # ====== 添加区域 ======
        add_frame = tk.LabelFrame(
            self.root, text=" 添加生日 ", font=("微软雅黑", 10, "bold"),
            bg="#f0f4f8", fg="#333", padx=15, pady=10
        )
        add_frame.pack(fill="x", padx=15, pady=(15, 5))

        row1 = tk.Frame(add_frame, bg="#f0f4f8")
        row1.pack(fill="x", pady=3)

        tk.Label(row1, text="姓名：", font=("微软雅黑", 10), bg="#f0f4f8").pack(side="left")
        self.name_entry = tk.Entry(row1, font=("微软雅黑", 10), width=20, relief="solid", bd=1)
        self.name_entry.pack(side="left", padx=(5, 20))

        tk.Label(row1, text="生日：", font=("微软雅黑", 10), bg="#f0f4f8").pack(side="left")
        self.date_entry = tk.Entry(row1, font=("微软雅黑", 10), width=14, relief="solid", bd=1)
        self.date_entry.pack(side="left", padx=5)
        tk.Label(
            row1, text="(格式: 2000-01-15)",
            font=("微软雅黑", 8), fg="#999", bg="#f0f4f8"
        ).pack(side="left", padx=5)

        btn_frame = tk.Frame(add_frame, bg="#f0f4f8")
        btn_frame.pack(fill="x", pady=(8, 0))

        tk.Button(
            btn_frame, text="➕ 添加", font=("微软雅黑", 10, "bold"),
            bg="#4a90d9", fg="white", relief="flat", cursor="hand2",
            width=12, command=self.add_birthday
        ).pack(side="left", padx=5)

        tk.Button(
            btn_frame, text="🗑️ 删除选中", font=("微软雅黑", 10),
            bg="#e74c3c", fg="white", relief="flat", cursor="hand2",
            width=12, command=self.delete_birthday
        ).pack(side="left", padx=5)

        tk.Button(
            btn_frame, text="🔍 检查提醒", font=("微软雅黑", 10),
            bg="#27ae60", fg="white", relief="flat", cursor="hand2",
            width=12, command=self.check_today
        ).pack(side="left", padx=5)

        # ====== 生日列表 ======
        list_frame = tk.LabelFrame(
            self.root, text=" 生日列表 ", font=("微软雅黑", 10, "bold"),
            bg="#f0f4f8", fg="#333", padx=10, pady=10
        )
        list_frame.pack(fill="both", expand=True, padx=15, pady=(5, 15))

        # Treeview 表格
        columns = ("name", "birthday", "age", "days_left", "status")
        self.tree = ttk.Treeview(
            list_frame, columns=columns, show="headings", height=12
        )

        self.tree.heading("name", text="姓名")
        self.tree.heading("birthday", text="出生日期")
        self.tree.heading("age", text="即将年龄")
        self.tree.heading("days_left", text="剩余天数")
        self.tree.heading("status", text="状态")

        self.tree.column("name", width=100, anchor="center")
        self.tree.column("birthday", width=120, anchor="center")
        self.tree.column("age", width=80, anchor="center")
        self.tree.column("days_left", width=80, anchor="center")
        self.tree.column("status", width=140, 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")

        # 配置行样式
        style = ttk.Style()
        style.configure("Treeview", font=("微软雅黑", 10), rowheight=28)
        style.configure("Treeview.Heading", font=("微软雅黑", 10, "bold"))

        # ====== 底部状态栏 ======
        self.status_label = tk.Label(
            self.root, text="就绪", font=("微软雅黑", 9),
            fg="#666", bg="#f0f4f8", anchor="w"
        )
        self.status_label.pack(fill="x", padx=15, pady=(0, 8))

    # ==================== 核心逻辑 ====================

    def add_birthday(self):
        name = self.name_entry.get().strip()
        date_str = self.date_entry.get().strip()

        if not name:
            messagebox.showwarning("提示", "请输入姓名！")
            return
        if not date_str:
            messagebox.showwarning("提示", "请输入出生日期！")
            return

        # 校验日期格式
        try:
            birth_date = datetime.strptime(date_str, "%Y-%m-%d").date()
        except ValueError:
            messagebox.showerror("错误", "日期格式不正确！请使用 YYYY-MM-DD 格式。")
            return

        if birth_date > date.today():
            messagebox.showerror("错误", "出生日期不能晚于今天！")
            return

        # 检查是否已存在
        for b in self.birthdays:
            if b["name"] == name:
                messagebox.showwarning("提示", f"「{name}」的生日已存在！")
                return

        self.birthdays.append({
            "name": name,
            "birthday": date_str
        })
        self.save_data()
        self.refresh_list()

        self.name_entry.delete(0, "end")
        self.date_entry.delete(0, "end")
        self.status_label.config(text=f"✅ 已添加「{name}」的生日")

    def delete_birthday(self):
        selected = self.tree.selection()
        if not selected:
            messagebox.showwarning("提示", "请先选中要删除的生日！")
            return

        names_to_delete = []
        for item in selected:
            values = self.tree.item(item, "values")
            names_to_delete.append(values[0])

        confirm = messagebox.askyesno("确认", f"确定要删除 {names_to_delete} 的生日记录吗？")
        if confirm:
            self.birthdays = [
                b for b in self.birthdays if b["name"] not in names_to_delete
            ]
            self.save_data()
            self.refresh_list()
            self.status_label.config(text=f"🗑️ 已删除 {names_to_delete}")

    def refresh_list(self):
        """刷新列表，计算倒计时"""
        self.tree.delete(*self.tree.get_children())
        today = date.today()

        # 按剩余天数排序
        items = []
        for b in self.birthdays:
            birth_date = datetime.strptime(b["birthday"], "%Y-%m-%d").date()
            days_left = self.days_until_birthday(birth_date)
            next_age = today.year - birth_date.year
            if (today.month, today.day) >= (birth_date.month, birth_date.day):
                next_age += 1

            if days_left == 0:
                status = "🎉 今天生日！"
            elif days_left <= 3:
                status = "🔔 即将到来"
            elif days_left <= 7:
                status = "📅 本周内"
            elif days_left <= 30:
                status = "📋 本月内"
            else:
                status = "—"

            items.append((b["name"], b["birthday"], next_age, days_left, status))

        items.sort(key=lambda x: x[3])

        for item in items:
            tag = ""
            if item[3] == 0:
                tag = "today"
            elif item[3] <= 3:
                tag = "soon"
            self.tree.insert("", "end", values=item, tags=(tag,))

        # 行颜色
        self.tree.tag_configure("today", background="#ffe0e0", foreground="#c0392b")
        self.tree.tag_configure("soon", background="#fff3cd", foreground="#856404")

        self.status_label.config(text=f"共 {len(self.birthdays)} 条生日记录")

    def days_until_birthday(self, birth_date):
        """计算距离下一个生日还有多少天"""
        today = date.today()
        # 今年的生日
        this_year_bday = date(today.year, birth_date.month, birth_date.day)
        if this_year_bday >= today:
            return (this_year_bday - today).days
        else:
            # 已过今年生日，算明年的
            next_year_bday = date(today.year + 1, birth_date.month, birth_date.day)
            return (next_year_bday - today).days

    # ==================== 提醒功能 ====================

    def check_today(self):
        """检查今天和近期是否有生日"""
        today = date.today()
        reminders = []

        for b in self.birthdays:
            birth_date = datetime.strptime(b["birthday"], "%Y-%m-%d").date()
            days_left = self.days_until_birthday(birth_date)

            if days_left == 0:
                reminders.append(f"🎉 今天是「{b['name']}」的生日！")
            elif days_left <= 3:
                reminders.append(f"🔔 「{b['name']}」的生日还有 {days_left} 天！")

        if reminders:
            msg = "\n".join(reminders)
            messagebox.showinfo("🎂 生日提醒", msg)
            self.status_label.config(text=f"⚠️ 有 {len(reminders)} 条生日提醒")
        else:
            self.status_label.config(text="✅ 近期没有生日提醒")
            messagebox.showinfo("生日提醒", "近期没有需要提醒的生日 😊")

    def periodic_check(self):
        """定时检查（后台静默，仅今天生日弹窗）"""
        today = date.today()
        for b in self.birthdays:
            birth_date = datetime.strptime(b["birthday"], "%Y-%m-%d").date()
            days_left = self.days_until_birthday(birth_date)
            if days_left == 0:
                messagebox.showinfo("🎂 生日提醒", f"今天是「{b['name']}」的生日！🎉")
        # 继续定时
        self.root.after(60000, self.periodic_check)


if __name__ == "__main__":
    root = tk.Tk()
    app = BirthdayReminder(root)
    root.mainloop()