# tang_poem_app.py
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
import json
import os
import sys

DEFAULT_JSON = [
    {
        "title": "静夜思",
        "author": "李白",
        "content": "床前明月光，\n疑是地上霜。\n举头望明月，\n低头思故乡。"
    },
    {
        "title": "登鹳雀楼",
        "author": "王之涣",
        "content": "白日依山尽，\n黄河入海流。\n欲穷千里目，\n更上一层楼。"
    },
    {
        "title": "春晓",
        "author": "孟浩然",
        "content": "春眠不觉晓，\n处处闻啼鸟。\n夜来风雨声，\n花落知多少。"
    },
    {
        "title": "枫桥夜泊",
        "author": "张继",
        "content": "月落乌啼霜满天，\n江枫渔火对愁眠。\n姑苏城外寒山寺，\n夜半钟声到客船。"
    }
]

DATA_FILENAME = "tang_poems.json"


class TangPoemApp:
    def __init__(self, master):
        self.master = master
        master.title("唐诗三百首")
        master.geometry("900x600")

        self.poems = self.ensure_and_load_poems()
        if not self.poems:
            messagebox.showerror("错误", "未能加载唐诗数据。")
            master.destroy()
            return

        self.create_widgets()
        self.populate_poem_list()

    def ensure_and_load_poems(self):
        """如果数据文件不存在则创建示例数据文件，然后加载它。"""
        file_path = DATA_FILENAME
        if not os.path.exists(file_path):
            try:
                with open(file_path, 'w', encoding='utf-8') as f:
                    json.dump(DEFAULT_JSON, f, ensure_ascii=False, indent=2)
            except Exception as e:
                print(f"无法创建默认数据文件: {e}", file=sys.stderr)
                return []

        try:
            with open(file_path, 'r', encoding='utf-8') as f:
                data = json.load(f)
                # 简单验证数据结构
                if isinstance(data, list):
                    return data
        except Exception as e:
            print(f"读取数据文件失败: {e}", file=sys.stderr)
            return []

        return []

    def create_widgets(self):
        main_frame = ttk.Frame(self.master, padding=8)
        main_frame.pack(fill=tk.BOTH, expand=True)

        # 顶部工具栏：搜索、加载文件、导出当前诗
        toolbar = ttk.Frame(main_frame)
        toolbar.pack(fill=tk.X, pady=(0, 6))

        ttk.Label(toolbar, text="搜索：").pack(side=tk.LEFT)
        self.search_var = tk.StringVar()
        self.search_entry = ttk.Entry(toolbar, textvariable=self.search_var)
        self.search_entry.pack(side=tk.LEFT, padx=(0, 6))
        self.search_entry.bind("<Return>", lambda e: self.search_poems())

        ttk.Button(toolbar, text="搜索", command=self.search_poems).pack(
            side=tk.LEFT, padx=(0, 6))
        ttk.Button(toolbar, text="重置", command=self.reset_search).pack(
            side=tk.LEFT, padx=(0, 6))
        ttk.Button(toolbar, text="加载 JSON...", command=self.load_json_file).pack(
            side=tk.LEFT, padx=(0, 6))
        ttk.Button(toolbar, text="导出当前诗...", command=self.export_current_poem).pack(
            side=tk.LEFT, padx=(0, 6))

        # 主体左右布局
        content_frame = ttk.Frame(main_frame)
        content_frame.pack(fill=tk.BOTH, expand=True)

        left_frame = ttk.Frame(content_frame, width=280)
        left_frame.pack(side=tk.LEFT, fill=tk.Y, padx=(0, 8))
        left_frame.pack_propagate(False)

        right_frame = ttk.Frame(content_frame)
        right_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True)

        # 左侧：列表与滚动条
        ttk.Label(left_frame, text="诗歌列表", font=(
            "宋体", 12, "bold")).pack(pady=(0, 6))

        self.poem_listbox = tk.Listbox(
            left_frame, font=("宋体", 12), exportselection=False)
        self.poem_listbox.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
        self.poem_listbox.bind('<<ListboxSelect>>', self.on_poem_select)

        list_scroll = ttk.Scrollbar(
            left_frame, orient=tk.VERTICAL, command=self.poem_listbox.yview)
        list_scroll.pack(side=tk.RIGHT, fill=tk.Y)
        self.poem_listbox.config(yscrollcommand=list_scroll.set)

        # 右侧：标题 作者 内容
        self.title_label = ttk.Label(
            right_frame, text="请选择一首诗", font=("宋体", 20, "bold"), anchor=tk.W)
        self.title_label.pack(fill=tk.X, pady=(0, 4), padx=4)

        self.author_label = ttk.Label(right_frame, text="", font=(
            "宋体", 14), foreground="gray", anchor=tk.W)
        self.author_label.pack(fill=tk.X, pady=(0, 6), padx=4)

        # 内容文本区（只读）
        self.content_text = tk.Text(right_frame, font=(
            "宋体", 14), wrap=tk.WORD, state=tk.DISABLED, padx=6, pady=6)
        self.content_text.pack(fill=tk.BOTH, expand=True,
                               side=tk.LEFT, padx=(0, 4), pady=(0, 4))

        content_scroll = ttk.Scrollbar(
            right_frame, orient=tk.VERTICAL, command=self.content_text.yview)
        content_scroll.pack(side=tk.RIGHT, fill=tk.Y, pady=(0, 4))
        self.content_text.config(yscrollcommand=content_scroll.set)

    def populate_poem_list(self, poems=None):
        """填充列表框。传入 poems 列表可用于显示搜索结果。"""
        if poems is None:
            poems = self.poems

        self.poem_listbox.delete(0, tk.END)
        for p in poems:
            title = p.get('title', '无题')
            author = p.get('author', '')
            display = f"{title} — {author}" if author else title
            self.poem_listbox.insert(tk.END, display)

        # 选中第一项
        if poems:
            self.poem_listbox.selection_set(0)
            self.on_poem_select(None)

        # 保存当前用于显示的列表（索引映射到原始 self.poems）
        self.current_display = poems

    def on_poem_select(self, event):
        sel = self.poem_listbox.curselection()
        if not sel:
            return
        idx = sel[0]
        try:
            poem = self.current_display[idx]
        except Exception:
            return

        title = poem.get('title', '')
        author = poem.get('author', '')
        content = poem.get('content', '')

        self.title_label.config(text=title)
        self.author_label.config(text=f"作者：{author}" if author else "")

        self.content_text.config(state=tk.NORMAL)
        self.content_text.delete(1.0, tk.END)
        self.content_text.insert(tk.END, content)
        self.content_text.config(state=tk.DISABLED)

    def search_poems(self):
        q = self.search_var.get().strip()
        if not q:
            self.populate_poem_list(self.poems)
            return
        q_lower = q.lower()
        results = []
        for p in self.poems:
            if q_lower in p.get('title', '').lower() or q_lower in p.get('author', '').lower() or q_lower in p.get('content', '').lower():
                results.append(p)
        if not results:
            messagebox.showinfo("搜索结果", "未找到匹配的诗歌。")
        self.populate_poem_list(results)

    def reset_search(self):
        self.search_var.set("")
        self.populate_poem_list(self.poems)

    def load_json_file(self):
        path = filedialog.askopenfilename(title="选择 JSON 文件", filetypes=[
                                          ("JSON 文件", "*.json"), ("所有文件", "*.*")])
        if not path:
            return
        try:
            with open(path, 'r', encoding='utf-8') as f:
                data = json.load(f)
            if not isinstance(data, list):
                messagebox.showerror("错误", "JSON 文件格式不正确，应为诗歌对象列表。")
                return
            # 简单验证对象结构
            for item in data:
                if not isinstance(item, dict) or 'title' not in item or 'content' not in item:
                    messagebox.showerror(
                        "错误", "JSON 中的每个对象应包含至少 'title' 和 'content' 字段。")
                    return
            self.poems = data
            self.reset_search()
            messagebox.showinfo(
                "成功", f"已从 {os.path.basename(path)} 加载 {len(self.poems)} 首诗。")
        except Exception as e:
            messagebox.showerror("错误", f"加载文件失败：{e}")

    def export_current_poem(self):
        sel = self.poem_listbox.curselection()
        if not sel:
            messagebox.showinfo("提示", "请先选择一首诗。")
            return
        idx = sel[0]
        try:
            poem = self.current_display[idx]
        except Exception:
            messagebox.showerror("错误", "获取当前诗歌失败。")
            return

        default_name = (poem.get('title') or 'poem') + ".txt"
        path = filedialog.asksaveasfilename(title="导出为文本", defaultextension=".txt", initialfile=default_name, filetypes=[
                                            ("文本文件", "*.txt"), ("所有文件", "*.*")])
        if not path:
            return
        try:
            with open(path, 'w', encoding='utf-8') as f:
                f.write(poem.get('title', '') + "\n")
                if poem.get('author'):
                    f.write("作者：" + poem.get('author') + "\n\n")
                f.write(poem.get('content', ''))
            messagebox.showinfo("导出成功", f"已导出到 {path}")
        except Exception as e:
            messagebox.showerror("错误", f"导出失败：{e}")


if __name__ == "__main__":
    root = tk.Tk()
    app = TangPoemApp(root)
    root.mainloop()
