import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import json
import os

class TravelPlannerApp:
    def __init__(self, root):
        self.root = root
        self.root.title("旅游计划助手")
        self.root.geometry("700x500")
        self.root.resizable(True, True)

        # 数据存储：每个计划是一个字典
        self.plans = []

        # 创建界面组件
        self.create_menu()
        self.create_input_frame()
        self.create_treeview()
        self.create_buttons()

    def create_menu(self):
        """创建菜单栏"""
        menubar = tk.Menu(self.root)
        # 文件菜单
        file_menu = tk.Menu(menubar, tearoff=0)
        file_menu.add_command(label="保存计划", command=self.save_plans)
        file_menu.add_command(label="打开计划", command=self.load_plans)
        file_menu.add_separator()
        file_menu.add_command(label="退出", command=self.root.quit)
        menubar.add_cascade(label="文件", menu=file_menu)
        self.root.config(menu=menubar)

    def create_input_frame(self):
        """创建输入区域"""
        frame = ttk.LabelFrame(self.root, text="添加新行程", padding=10)
        frame.pack(fill=tk.X, padx=10, pady=5)

        # 目的地
        ttk.Label(frame, text="目的地:").grid(row=0, column=0, sticky=tk.W, padx=5, pady=2)
        self.dest_entry = ttk.Entry(frame, width=20)
        self.dest_entry.grid(row=0, column=1, padx=5, pady=2)

        # 日期
        ttk.Label(frame, text="日期 (YYYY-MM-DD):").grid(row=0, column=2, sticky=tk.W, padx=5, pady=2)
        self.date_entry = ttk.Entry(frame, width=15)
        self.date_entry.grid(row=0, column=3, padx=5, pady=2)

        # 活动
        ttk.Label(frame, text="活动:").grid(row=0, column=4, sticky=tk.W, padx=5, pady=2)
        self.act_entry = ttk.Entry(frame, width=30)
        self.act_entry.grid(row=0, column=5, padx=5, pady=2)

        # 添加按钮
        add_btn = ttk.Button(frame, text="添加计划", command=self.add_plan)
        add_btn.grid(row=0, column=6, padx=10, pady=2)

    def create_treeview(self):
        """创建表格显示计划"""
        tree_frame = ttk.Frame(self.root)
        tree_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)

        # 定义列
        columns = ("destination", "date", "activity")
        self.tree = ttk.Treeview(tree_frame, columns=columns, show="headings", height=15)

        # 设置列标题
        self.tree.heading("destination", text="目的地")
        self.tree.heading("date", text="日期")
        self.tree.heading("activity", text="活动")

        # 列宽
        self.tree.column("destination", width=150, anchor=tk.CENTER)
        self.tree.column("date", width=120, anchor=tk.CENTER)
        self.tree.column("activity", width=300, anchor=tk.W)

        # 滚动条
        scrollbar = ttk.Scrollbar(tree_frame, orient=tk.VERTICAL, command=self.tree.yview)
        self.tree.configure(yscrollcommand=scrollbar.set)

        self.tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)

    def create_buttons(self):
        """操作按钮：删除、清空"""
        btn_frame = ttk.Frame(self.root)
        btn_frame.pack(pady=5)

        del_btn = ttk.Button(btn_frame, text="删除选中计划", command=self.delete_selected)
        del_btn.pack(side=tk.LEFT, padx=5)

        clear_btn = ttk.Button(btn_frame, text="清空所有计划", command=self.clear_all)
        clear_btn.pack(side=tk.LEFT, padx=5)

    # ------------------- 数据操作 -------------------
    def add_plan(self):
        """添加一条计划到列表和表格"""
        destination = self.dest_entry.get().strip()
        date = self.date_entry.get().strip()
        activity = self.act_entry.get().strip()

        if not destination or not date or not activity:
            messagebox.showwarning("输入不完整", "请填写目的地、日期和活动。")
            return

        # 简单日期格式校验
        if not self.is_valid_date(date):
            messagebox.showwarning("日期格式错误", "请输入 YYYY-MM-DD 格式的日期。")
            return

        plan = {"destination": destination, "date": date, "activity": activity}
        self.plans.append(plan)
        self.refresh_treeview()

        # 清空输入框
        self.dest_entry.delete(0, tk.END)
        self.date_entry.delete(0, tk.END)
        self.act_entry.delete(0, tk.END)

    def refresh_treeview(self):
        """刷新表格显示"""
        for item in self.tree.get_children():
            self.tree.delete(item)
        for plan in self.plans:
            self.tree.insert("", tk.END, values=(plan["destination"], plan["date"], plan["activity"]))

    def delete_selected(self):
        """删除表格中选中的计划"""
        selected = self.tree.selection()
        if not selected:
            messagebox.showinfo("未选择", "请先在表格中选择一条计划。")
            return
        # 获取选中项的索引（通过values比对）
        for item in selected:
            values = self.tree.item(item, "values")
            # 从plans中删除匹配的字典
            self.plans = [p for p in self.plans 
                          if not (p["destination"] == values[0] and p["date"] == values[1] and p["activity"] == values[2])]
        self.refresh_treeview()

    def clear_all(self):
        """清空所有计划"""
        if not self.plans:
            return
        if messagebox.askyesno("确认清空", "确定要清空所有计划吗？"):
            self.plans.clear()
            self.refresh_treeview()

    # ------------------- 文件保存/加载 -------------------
    def save_plans(self):
        """保存为 JSON 文件"""
        if not self.plans:
            messagebox.showinfo("无计划", "当前没有任何计划可以保存。")
            return
        file_path = filedialog.asksaveasfilename(
            defaultextension=".json",
            filetypes=[("JSON 文件", "*.json"), ("所有文件", "*.*")],
            title="保存旅游计划"
        )
        if not file_path:
            return
        try:
            with open(file_path, "w", encoding="utf-8") as f:
                json.dump(self.plans, f, ensure_ascii=False, indent=2)
            messagebox.showinfo("成功", f"计划已保存到:\n{file_path}")
        except Exception as e:
            messagebox.showerror("保存失败", f"发生错误: {e}")

    def load_plans(self):
        """从 JSON 文件加载计划"""
        file_path = filedialog.askopenfilename(
            filetypes=[("JSON 文件", "*.json"), ("所有文件", "*.*")],
            title="打开旅游计划"
        )
        if not file_path:
            return
        try:
            with open(file_path, "r", encoding="utf-8") as f:
                data = json.load(f)
            if not isinstance(data, list):
                raise ValueError("文件格式不正确，应为列表。")
            # 简单验证每个元素是否包含必要字段
            for item in data:
                if not all(k in item for k in ("destination", "date", "activity")):
                    raise ValueError("计划项缺少必要字段(destination, date, activity)。")
            self.plans = data
            self.refresh_treeview()
            messagebox.showinfo("成功", f"已加载 {len(data)} 条计划。")
        except Exception as e:
            messagebox.showerror("加载失败", f"无法打开文件:\n{e}")

    @staticmethod
    def is_valid_date(date_str):
        """校验日期格式 YYYY-MM-DD"""
        try:
            parts = date_str.split("-")
            if len(parts) != 3:
                return False
            year, month, day = int(parts[0]), int(parts[1]), int(parts[2])
            if not (1 <= month <= 12) or not (1 <= day <= 31):
                return False
            return True
        except ValueError:
            return False

# ------------------- 程序入口 -------------------
if __name__ == "__main__":
    root = tk.Tk()
    app = TravelPlannerApp(root)
    root.mainloop()