import tkinter as tk
from tkinter import messagebox, filedialog
import json
import random
import math
import colorsys

# ========================
# 全局配置
# ========================
WIDTH, HEIGHT = 900, 640

# ========================
# 主题
# ========================
THEMES = {
    "🌸 樱花粉": {"bg": "#FFF0F5", "fg": "#C2185B", "panel": "#FCE4EC", "btn": "#F48FB1", "accent": "#E91E63", "card": "#FFF9FC"},
    "💙 天空蓝": {"bg": "#E3F2FD", "fg": "#0D47A1", "panel": "#BBDEFB", "btn": "#42A5F5", "accent": "#1565C0", "card": "#F0F8FF"},
    "💚 抹茶绿": {"bg": "#E8F5E9", "fg": "#1B5E20", "panel": "#C8E6C9", "btn": "#66BB6A", "accent": "#2E7D32", "card": "#F5FFF5"},
    "🧡 蜜桔橙": {"bg": "#FFF3E0", "fg": "#E65100", "panel": "#FFE0B2", "btn": "#FF9800", "accent": "#EF6C00", "card": "#FFF8F0"},
    "💜 梦幻紫": {"bg": "#F3E5F5", "fg": "#4A148C", "panel": "#E1BEE7", "btn": "#AB47BC", "accent": "#7B1FA2", "card": "#FBF0FF"},
    "🖤 暗夜灰": {"bg": "#263238", "fg": "#ECEFF1", "panel": "#37474F", "btn": "#546E7A", "accent": "#FF6E40", "card": "#455A64"},
}
cur_theme = "🌸 樱花粉"

# ========================
# 数据模型
# ========================
surveys = []       # 所有投票/调查
cur_survey = None  # 当前选中的
cur_sid = 0
has_voted = set()  # 已投票的 survey id 集合（模拟用）

# ========================
# UI 引用
# ========================
root = None
canvas = None
lbl_title = None
lbl_stats = None
lbl_info = None
lbl_status = None
theme_btns = []
all_widgets = []
btn_list = []

# ========================
# 工具函数
# ========================
def gen_id():
    global cur_sid
    cur_sid += 1
    return cur_sid

def get_text_color(hex_str):
    h = hex_str.lstrip("#")
    r, g, b = [int(h[i:i+2], 16) for i in (0, 2, 4)]
    bright = 0.299*r + 0.587*g + 0.114*b
    return "#FFFFFF" if bright < 140 else "#212121"

def hsl_to_hex(h, s, l):
    s /= 100; l /= 100
    if s == 0:
        v = int(l*255)
        return f"#{v:02x}{v:02x}{v:02x}"
    h /= 360
    if l < 0.5: q = l*(1+s)
    else: q = l+s-l*s
    p = 2*l-q
    def hue(t):
        if t < 0: t += 1
        if t > 1: t -= 1
        if t < 1/6: return p+(q-p)*6*t
        if t < 1/2: return q
        if t < 2/3: return p+(q-p)*(2/3-t)*6
        return p
    r, g, b = int(hue(h+1/3)*255), int(hue(h)*255), int(hue(h-1/3)*255)
    return f"#{r:02x}{g:02x}{b:02x}"

def gen_palette(n):
    """生成和谐配色"""
    base_h = random.random() * 360
    palette = []
    for i in range(n):
        h = (base_h + i * (360/n)) % 360
        s = random.randint(55, 90)
        l = random.randint(45, 75)
        palette.append(hsl_to_hex(h, s, l))
    return palette

# ========================
# 调查数据模型
# ========================
def new_survey(title, desc, stype, options):
    """创建新调查"""
    s = {
        "id": gen_id(),
        "title": title,
        "desc": desc,
        "type": stype,  # "single" / "multi" / "rating" / "text"
        "options": options,  # [{text, votes, color}]
        "total_votes": 0,
        "voters": [],  # 模拟投票记录
        "created": "",  # 可以加时间戳
    }
    surveys.append(s)
    return s

def vote(survey, opt_idx, voter_name=None):
    """投票"""
    if survey["id"] in has_voted and voter_name is None:
        return False, "你已经投过票了！"
    
    if survey["type"] == "single":
        survey["options"][opt_idx]["votes"] += 1
        survey["total_votes"] += 1
        if voter_name:
            survey["voters"].append(voter_name)
        has_voted.add(survey["id"])
        return True, "投票成功！"
    elif survey["type"] == "multi":
        survey["options"][opt_idx]["votes"] += 1
        survey["total_votes"] += 1
        return True, "投票成功！"
    elif survey["type"] == "rating":
        survey["options"][opt_idx]["votes"] += 1
        survey["total_votes"] += 1
        return True, f"你给了 {opt_idx+1} 星！"
    return False, "不支持的类型"

def simulate_votes(survey, count=None):
    """模拟随机投票"""
    if not count:
        count = random.randint(20, 100)
    
    for _ in range(count):
        if survey["type"] in ("single", "rating"):
            idx = random.randint(0, len(survey["options"]) - 1)
            survey["options"][idx]["votes"] += 1
            survey["total_votes"] += 1
        elif survey["type"] == "multi":
            for i in range(len(survey["options"])):
                if random.random() < 0.4:
                    survey["options"][i]["votes"] += 1
                    survey["total_votes"] += 1
    
    return count

# ========================
# 预设调查模板
# ========================
def load_templates():
    """加载预设调查"""
    templates = [
        {
            "title": "🏫 最喜欢的学习科目",
            "desc": "选出你最喜欢的科目，看看大家的选择！",
            "type": "single",
            "options": ["语文", "数学", "英语", "物理", "化学", "生物", "历史", "地理"]
        },
        {
            "title": "🎮 你最喜欢的游戏类型",
            "desc": "可以多选哦~",
            "type": "multi",
            "options": ["动作冒险", "角色扮演", "策略战棋", "模拟经营", "射击", "体育竞速", "益智解谜", "音乐节奏"]
        },
        {
            "title": "⭐ 食堂饭菜满意度",
            "desc": "给食堂打个分吧！",
            "type": "rating",
            "options": ["1星", "2星", "3星", "4星", "5星"]
        },
        {
            "title": "🌈 最喜欢的颜色",
            "desc": "选一个代表你的颜色！",
            "type": "single",
            "options": ["红色", "蓝色", "绿色", "黄色", "紫色", "橙色", "粉色", "黑色"]
        },
        {
            "title": "📱 每天使用手机时长",
            "desc": "诚实一点~",
            "type": "single",
            "options": ["<1小时", "1-3小时", "3-5小时", "5-8小时", ">8小时"]
        },
        {
            "title": "🎵 喜欢的音乐风格",
            "desc": "可以多选！",
            "type": "multi",
            "options": ["流行", "摇滚", "古典", "电子", "民谣", "爵士", "说唱", "国风"]
        },
        {
            "title": "🏃 运动频率调查",
            "desc": "你多久运动一次？",
            "type": "single",
            "options": ["每天", "每周3-5次", "每周1-2次", "偶尔", "几乎不运动"]
        },
        {
            "title": "💤 每天睡眠时间",
            "desc": "睡眠充足吗？",
            "type": "single",
            "options": ["<5小时", "5-6小时", "6-7小时", "7-8小时", ">8小时"]
        },
    ]
    
    for tpl in templates:
        colors = gen_palette(len(tpl["options"]))
        opts = [{"text": o, "votes": 0, "color": c} for o, c in zip(tpl["options"], colors)]
        s = new_survey(tpl["title"], tpl["desc"], tpl["type"], opts)
        # 自动模拟一些投票
        simulate_votes(s, random.randint(15, 60))

# ========================
# 保存/加载
# ========================
def save_data():
    path = filedialog.asksaveasfilename(
        defaultextension=".json",
        filetypes=[("JSON", "*.json")]
    )
    if not path:
        return
    data = {
        "surveys": surveys,
        "cur_sid": cur_sid,
    }
    with open(path, "w", encoding="utf-8") as f:
        json.dump(data, f, ensure_ascii=False, indent=2)
    log_msg(f"💾 已保存数据")

def load_data():
    path = filedialog.askopenfilename(filetypes=[("JSON", "*.json")])
    if not path:
        return
    global surveys, cur_sid
    try:
        with open(path, "r", encoding="utf-8") as f:
            data = json.load(f)
        surveys = data.get("surveys", [])
        cur_sid = data.get("cur_sid", 0)
        has_voted.clear()
        log_msg(f"📂 已加载 {len(surveys)} 个调查")
    except Exception as e:
        log_msg(f"❌ 加载失败: {e}")

# ========================
# 创建自定义调查
# ========================
def create_survey_dialog():
    """创建调查弹窗"""
    dlg = tk.Toplevel(root)
    dlg.title("✨ 创建新调查")
    dlg.geometry("460x420")
    dlg.resizable(False, False)
    dlg.transient(root)
    dlg.grab_set()
    
    t = THEMES[cur_theme]
    dlg.configure(bg=t["bg"])
    
    tk.Label(dlg, text="📝 调查标题：", font=("Comic Sans MS", 11, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(anchor="w", padx=15, pady=(15,2))
    entry_title = tk.Entry(dlg, font=("Comic Sans MS", 12), width=35)
    entry_title.pack(padx=15, pady=2)
    entry_title.insert(0, "我最喜欢的____")
    
    tk.Label(dlg, text="📋 描述说明：", font=("Comic Sans MS", 11, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(anchor="w", padx=15, pady=(10,2))
    entry_desc = tk.Entry(dlg, font=("Comic Sans MS", 11), width=35)
    entry_desc.pack(padx=15, pady=2)
    entry_desc.insert(0, "选一个你最喜欢的吧~")
    
    tk.Label(dlg, text="📊 投票类型：", font=("Comic Sans MS", 11, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(anchor="w", padx=15, pady=(10,2))
    
    type_var = tk.StringVar(value="single")
    tf = tk.Frame(dlg, bg=t["bg"])
    tf.pack(padx=15, pady=2, anchor="w")
    tk.Radiobutton(tf, text="单选", variable=type_var, value="single",
                   font=("Comic Sans MS", 10), bg=t["bg"]).pack(side="left", padx=5)
    tk.Radiobutton(tf, text="多选", variable=type_var, value="multi",
                   font=("Comic Sans MS", 10), bg=t["bg"]).pack(side="left", padx=5)
    tk.Radiobutton(tf, text="评分(1-5星)", variable=type_var, value="rating",
                   font=("Comic Sans MS", 10), bg=t["bg"]).pack(side="left", padx=5)
    
    tk.Label(dlg, text="📝 选项（每行一个）：", font=("Comic Sans MS", 11, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(anchor="w", padx=15, pady=(10,2))
    txt_opts = tk.Text(dlg, font=("Comic Sans MS", 10), width=35, height=5)
    txt_opts.pack(padx=15, pady=2)
    txt_opts.insert("1.0", "选项A\n选项B\n选项C\n选项D")
    
    def do_create():
        title = entry_title.get().strip()
        desc = entry_desc.get().strip()
        stype = type_var.get()
        opts_text = txt_opts.get("1.0", "end").strip().split("\n")
        opts = [o.strip() for o in opts_text if o.strip()]
        
        if not title:
            messagebox.showwarning("提示", "请填写标题！", parent=dlg)
            return
        if len(opts) < 2:
            messagebox.showwarning("提示", "至少需要2个选项！", parent=dlg)
            return
        
        colors = gen_palette(len(opts))
        opt_objs = [{"text": o, "votes": 0, "color": c} for o, c in zip(opts, colors)]
        s = new_survey(title, desc, stype, opt_objs)
        simulate_votes(s, random.randint(10, 40))
        log_msg(f"✨ 已创建: {title}")
        set_cur_survey(s)
        dlg.destroy()
    
    btn_frame = tk.Frame(dlg, bg=t["bg"])
    btn_frame.pack(pady=15)
    tk.Button(btn_frame, text="✅ 创建", font=("Comic Sans MS", 11, "bold"),
              bg=t["accent"], fg="white", padx=20, command=do_create).pack(side="left", padx=10)
    tk.Button(btn_frame, text="❌ 取消", font=("Comic Sans MS", 10),
              command=dlg.destroy).pack(side="left", padx=10)

# ========================
# 投票弹窗
# ========================
def vote_dialog(survey):
    """投票弹窗"""
    dlg = tk.Toplevel(root)
    dlg.title(f"🗳️ 投票: {survey['title']}")
    dlg.geometry("420x400")
    dlg.resizable(False, False)
    dlg.transient(root)
    dlg.grab_set()
    
    t = THEMES[cur_theme]
    dlg.configure(bg=t["bg"])
    
    tk.Label(dlg, text=survey["title"], font=("Comic Sans MS", 14, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(pady=(15,5))
    tk.Label(dlg, text=survey["desc"], font=("Comic Sans MS", 10),
             bg=t["bg"], fg=t["accent"]).pack(pady=2)
    
    tk.Label(dlg, text=f"类型: {'单选' if survey['type']=='single' else '多选' if survey['type']=='multi' else '⭐评分'}",
             font=("Comic Sans MS", 9), bg=t["bg"], fg=t["fg"]).pack(pady=2)
    
    selected = set()
    
    def toggle_opt(idx):
        if survey["type"] == "single":
            selected.clear()
            selected.add(idx)
            for btn in opt_btns:
                btn.config(relief="raised", bg=t["panel"])
            opt_btns[idx].config(relief="sunken", bg=t["accent"])
        elif survey["type"] == "multi":
            if idx in selected:
                selected.remove(idx)
                opt_btns[idx].config(relief="raised", bg=t["panel"])
            else:
                selected.add(idx)
                opt_btns[idx].config(relief="sunken", bg=t["accent"])
        elif survey["type"] == "rating":
            selected.clear()
            selected.add(idx)
            for btn in opt_btns:
                btn.config(relief="raised", bg=t["panel"])
            opt_btns[idx].config(relief="sunken", bg=t["accent"])
    
    opt_frame = tk.Frame(dlg, bg=t["bg"])
    opt_frame.pack(pady=10, padx=20, fill="both", expand=True)
    
    opt_btns = []
    for i, opt in enumerate(survey["options"]):
        btn = tk.Button(opt_frame, text=f"  {opt['text']}  ",
                         font=("Comic Sans MS", 11), bg=t["panel"],
                         relief="raised", bd=2, anchor="w",
                         command=lambda idx=i: toggle_opt(idx))
        btn.pack(fill="x", pady=2)
        opt_btns.append(btn)
    
    def do_vote():
        if not selected:
            messagebox.showwarning("提示", "请至少选一个选项！", parent=dlg)
            return
        for idx in selected:
            survey["options"][idx]["votes"] += 1
            survey["total_votes"] += 1
        has_voted.add(survey["id"])
        log_msg(f"🗳️ 已投票: {survey['title']}")
        dlg.destroy()
        draw_survey()
    
    btn_f = tk.Frame(dlg, bg=t["bg"])
    btn_f.pack(pady=10)
    tk.Button(btn_f, text="✅ 提交投票", font=("Comic Sans MS", 11, "bold"),
              bg=t["accent"], fg="white", padx=15, command=do_vote).pack(side="left", padx=8)
    tk.Button(btn_f, text="❌ 取消", command=dlg.destroy).pack(side="left", padx=8)

# ========================
# 查看详情
# ========================
def view_details(survey):
    """查看调查详情"""
    dlg = tk.Toplevel(root)
    dlg.title(f"📊 {survey['title']}")
    dlg.geometry("500x500")
    dlg.transient(root)
    dlg.grab_set()
    
    t = THEMES[cur_theme]
    dlg.configure(bg=t["bg"])
    
    tk.Label(dlg, text=survey["title"], font=("Comic Sans MS", 14, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(pady=(15,5))
    tk.Label(dlg, text=survey["desc"], font=("Comic Sans MS", 10),
             bg=t["bg"], fg=t["accent"]).pack(pady=2)
    tk.Label(dlg, text=f"总投票数: {survey['total_votes']}", font=("Comic Sans MS", 11, "bold"),
             bg=t["bg"], fg=t["fg"]).pack(pady=5)
    
    # 详细列表
    detail_frame = tk.Frame(dlg, bg=t["bg"])
    detail_frame.pack(fill="both", expand=True, padx=20, pady=10)
    
    for opt in survey["options"]:
        pct = (opt["votes"] / survey["total_votes"] * 100) if survey["total_votes"] > 0 else 0
        row = tk.Frame(detail_frame, bg=t["bg"])
        row.pack(fill="x", pady=2)
        
        # 色块
        color_box = tk.Frame(row, width=16, height=16, bg=opt["color"])
        color_box.pack(side="left", padx=(0,8), pady=2)
        
        tk.Label(row, text=f"{opt['text']}", font=("Comic Sans MS", 10),
                 bg=t["bg"], fg=t["fg"], width=15, anchor="w").pack(side="left")
        tk.Label(row, text=f"{opt['votes']} 票", font=("Comic Sans MS", 10, "bold"),
                 bg=t["bg"], fg=t["accent"], width=8).pack(side="left")
        tk.Label(row, text=f"{pct:.1f}%", font=("Comic Sans MS", 10),
                 bg=t["bg"], fg=t["fg"], width=8).pack(side="left")
        
        # 进度条
        bar_w = int(pct * 2)
        bar = tk.Frame(row, width=bar_w, height=12, bg=opt["color"])
        bar.pack(side="left", padx=5)
    
    # 投票记录
    if survey["voters"]:
        tk.Label(dlg, text=f"📋 投票记录 ({len(survey['voters'])}人):",
                 font=("Comic Sans MS", 10, "bold"), bg=t["bg"], fg=t["fg"]).pack(anchor="w", padx=20, pady=(10,2))
        txt = tk.Text(dlg, font=("Consolas", 9), height=6, width=50)
        txt.pack(padx=20, pady=2)
        for name in survey["voters"]:
            txt.insert("end", f"  {name}\n")
        txt.config(state="disabled")
    
    tk.Button(dlg, text="关闭", command=dlg.destroy).pack(pady=10)

# ========================
# 绘图
# ========================
def draw_survey():
    """绘制当前调查"""
    canvas.delete("all")
    t = THEMES[cur_theme]
    
    if not cur_survey:
        # 总览
        draw_overview()
        return
    
    s = cur_survey
    y = 20
    
    # 标题区
    canvas.create_rectangle(15, y, WIDTH-15, y+70, fill=t["card"], outline=t["accent"], width=2, tags="survey")
    canvas.create_text(30, y+15, text=s["title"], font=("Comic Sans MS", 16, "bold"),
                       fill=t["fg"], anchor="w", tags="survey")
    canvas.create_text(30, y+38, text=s["desc"], font=("Comic Sans MS", 10),
                       fill=t["accent"], anchor="w", tags="survey")
    
    type_text = {"single": "🔘 单选", "multi": "☑️ 多选", "rating": "⭐ 评分"}[s["type"]]
    canvas.create_text(WIDTH-40, y+15, text=type_text, font=("Comic Sans MS", 10),
                       fill=t["accent"], anchor="e", tags="survey")
    canvas.create_text(WIDTH-40, y+38, text=f"总票数: {s['total_votes']}", font=("Comic Sans MS", 11, "bold"),
                       fill=t["fg"], anchor="e", tags="survey")
    
    # 进度条图
    y += 85
    max_votes = max(o["votes"] for o in s["options"]) if s["options"] else 1
    
    for i, opt in enumerate(s["options"]):
        oy = y + i * 55
        pct = (opt["votes"] / s["total_votes"] * 100) if s["total_votes"] > 0 else 0
        bar_w = int((opt["votes"] / max_votes) * (WIDTH - 200)) if max_votes > 0 else 0
        
        # 背景条
        canvas.create_rectangle(30, oy, WIDTH-100, oy+35, fill=t["panel"], outline="#999", tags="survey")
        # 填充条
        if bar_w > 0:
            canvas.create_rectangle(30, oy, 30+bar_w, oy+35, fill=opt["color"], outline="", tags="survey")
        
        # 文字
        txt_c = get_text_color(opt["color"]) if bar_w > 80 else t["fg"]
        canvas.create_text(40, oy+17, text=f"{opt['text']}", font=("Comic Sans MS", 11, "bold"),
                           fill=txt_c, anchor="w", tags="survey")
        canvas.create_text(WIDTH-115, oy+17, text=f"{opt['votes']}票 ({pct:.1f}%)",
                           font=("Comic Sans MS", 10), fill=t["fg"], anchor="e", tags="survey")
        
        # 投票按钮（点击区域）
        btn_id = f"vote_opt_{i}"
        canvas.create_rectangle(WIDTH-90, oy, WIDTH-30, oy+35, fill=t["btn"], outline="#333",
                                tags=("survey", "vote_btn", btn_id))
        canvas.create_text(WIDTH-60, oy+17, text="投", font=("Comic Sans MS", 10, "bold"),
                           fill="white", tags=("survey", btn_id))
    
    # 底部按钮
    y += len(s["options"]) * 55 + 20
    btn_y = y
    
    # 模拟投票
    canvas.create_rectangle(30, btn_y, 150, btn_y+30, fill="#7B1FA2", outline="",
                            tags=("survey", "btn_simulate"))
    canvas.create_text(90, btn_y+15, text="🎲 模拟投票", font=("Comic Sans MS", 10, "bold"),
                       fill="white", tags=("survey", "btn_simulate"))
    
    # 查看详情
    canvas.create_rectangle(165, btn_y, 285, btn_y+30, fill=t["accent"], outline="",
                            tags=("survey", "btn_details"))
    canvas.create_text(225, btn_y+15, text="📊 查看详情", font=("Comic Sans MS", 10, "bold"),
                       fill="white", tags=("survey", "btn_details"))
    
    # 返回
    canvas.create_rectangle(300, btn_y, 380, btn_y+30, fill=t["btn"], outline="",
                            tags=("survey", "btn_back"))
    canvas.create_text(340, btn_y+15, text="⬅️ 返回总览", font=("Comic Sans MS", 10, "bold"),
                       fill="white", tags=("survey", "btn_back"))
    
    # 删除
    canvas.create_rectangle(WIDTH-130, btn_y, WIDTH-30, btn_y+30, fill="#F44336", outline="",
                            tags=("survey", "btn_delete"))
    canvas.create_text(WIDTH-80, btn_y+15, text="🗑️ 删除", font=("Comic Sans MS", 10, "bold"),
                       fill="white", tags=("survey", "btn_delete"))
    
    # 统计摘要
    if s["total_votes"] > 0:
        sorted_opts = sorted(s["options"], key=lambda o: o["votes"], reverse=True)
        winner = sorted_opts[0]
        y2 = btn_y + 45
        canvas.create_text(30, y2, text=f"🏆 当前领先: {winner['text']} ({winner['votes']}票)",
                           font=("Comic Sans MS", 11, "bold"), fill=t["accent"], anchor="w",
                           tags="survey")
        
        # 饼图
        pie_x, pie_y = WIDTH - 100, y2 + 80
        pie_r = 55
        start_angle = 0
        for opt in s["options"]:
            if opt["votes"] == 0: continue
            angle = opt["votes"] / s["total_votes"] * 360
            canvas.create_arc(pie_x-pie_r, pie_y-pie_r, pie_x+pie_r, pie_y+pie_r,
                              start=start_angle, extent=angle, fill=opt["color"],
                              outline=t["bg"], tags="survey")
            start_angle += angle
        canvas.create_oval(pie_x-3, pie_y-3, pie_x+3, pie_y+3, fill=t["fg"], tags="survey")
        canvas.create_text(pie_x, pie_y+pie_r+15, text="饼图", font=("Comic Sans MS", 9),
                           fill=t["fg"], tags="survey")

def draw_overview():
    """绘制总览"""
    t = THEMES[cur_theme]
    canvas.delete("all")
    
    y = 20
    canvas.create_text(WIDTH//2, y, text="📊 投票/调查总览", font=("Comic Sans MS", 20, "bold"),
                       fill=t["fg"], tags="overview")
    
    y += 30
    canvas.create_text(WIDTH//2, y, text=f"共 {len(surveys)} 个调查 | 总投票 {sum(s['total_votes'] for s in surveys)} 次",
                       font=("Comic Sans MS", 11), fill=t["accent"], tags="overview")
    
    y += 15
    # 调查卡片
    card_w = 190
    card_h = 120
    cols = 4
    gap = 15
    start_x = (WIDTH - cols * card_w - (cols-1) * gap) // 2
    start_y = y + 10
    
    for i, s in enumerate(surveys):
        col = i % cols
        row = i // cols
        cx = start_x + col * (card_w + gap)
        cy = start_y + row * (card_h + gap)
        
        # 卡片背景
        canvas.create_rectangle(cx, cy, cx+card_w, cy+card_h, fill=t["card"],
                                outline=t["accent"], width=2, tags="overview")
        
        # 标题
        title = s["title"][:12] + "..." if len(s["title"]) > 12 else s["title"]
        canvas.create_text(cx+10, cy+12, text=title, font=("Comic Sans MS", 11, "bold"),
                           fill=t["fg"], anchor="w", tags="overview")
        
        # 类型
        type_icon = {"single": "🔘", "multi": "☑️", "rating": "⭐"}[s["type"]]
        canvas.create_text(cx+10, cy+32, text=f"{type_icon} {s['type']}", font=("Comic Sans MS", 9),
                           fill=t["accent"], anchor="w", tags="overview")
        
        # 投票数
        canvas.create_text(cx+10, cy+50, text=f"🗳️ {s['total_votes']} 票",
                           font=("Comic Sans MS", 10), fill=t["fg"], anchor="w", tags="overview")
        
        # 领先者
        if s["options"] and s["total_votes"] > 0:
            winner = max(s["options"], key=lambda o: o["votes"])
            canvas.create_text(cx+10, cy+70, text=f"🏆 {winner['text']}",
                               font=("Comic Sans MS", 9, "bold"), fill=t["accent"], anchor="w",
                               tags="overview")
        
        # 色条（选项预览）
        bar_y = cy + card_h - 12
        total_w = card_w - 20
        cur_x = cx + 10
        for opt in s["options"][:6]:
            if s["total_votes"] > 0:
                w = int(opt["votes"] / s["total_votes"] * total_w)
            else:
                w = total_w // len(s["options"])
            if w > 0:
                canvas.create_rectangle(cur_x, bar_y, cur_x+w, bar_y+8, fill=opt["color"],
                                        outline="", tags="overview")
                cur_x += w
        
        # 点击区域
        canvas.create_rectangle(cx, cy, cx+card_w, cy+card_h, fill="", outline="",
                                tags=("overview", "survey_card", f"card_{s['id']}"))
    
    # 底部提示
    y_end = start_y + ((len(surveys)-1)//cols + 1) * (card_h + gap) + 20
    canvas.create_text(WIDTH//2, y_end, text="💡 点击卡片查看详情和投票 | 点「✨ 新建调查」创建更多",
                       font=("Comic Sans MS", 10), fill=t["accent"], tags="overview")

# ========================
# 画布点击
# ========================
def on_canvas_click(e):
    """处理画布点击"""
    tags = canvas.find_closest(e.x, e.y)
    if not tags:
        return
    tag = canvas.gettags(tags[0])
    
    for t in tag:
        if t.startswith("card_"):
            sid = int(t.split("_")[1])
            for s in surveys:
                if s["id"] == sid:
                    set_cur_survey(s)
                    return
        if t == "btn_simulate" and cur_survey:
            count = simulate_votes(cur_survey)
            log_msg(f"🎲 模拟了 {count} 票")
            draw_survey()
            return
        if t == "btn_details" and cur_survey:
            view_details(cur_survey)
            return
        if t == "btn_back":
            set_cur_survey(None)
            return
        if t == "btn_delete" and cur_survey:
            if messagebox.askyesno("确认", f"删除「{cur_survey['title']}」？"):
                surveys.remove(cur_survey)
                set_cur_survey(None)
                log_msg(f"🗑️ 已删除调查")
            return
        if t.startswith("vote_opt_") and cur_survey:
            idx = int(t.split("_")[-1])
            ok, msg = vote(cur_survey, idx)
            log_msg(f"{'✅' if ok else '⚠️'} {msg}")
            if ok: draw_survey()
            return

# ========================
# 设置当前调查
# ========================
def set_cur_survey(s):
    global cur_survey
    cur_survey = s
    draw_survey()

# ========================
# 日志
# ========================
log_lines = []
def log_msg(msg):
    global log_lines
    log_lines.append(msg)
    if len(log_lines) > 5:
        log_lines.pop(0)
    if lbl_status:
        lbl_status.config(text=" | ".join(log_lines[-3:]))

# ========================
# 换肤
# ========================
def apply_theme(name):
    global cur_theme
    cur_theme = name
    t = THEMES[name]
    
    root.config(bg=t["bg"])
    for w in all_widgets:
        try:
            w.config(bg=t["bg"], fg=t["fg"])
        except:
            pass
    
    for btn in theme_btns:
        btn.config(bg=t["btn"], fg="white")
    
    draw_survey()

# ========================
# 构建界面
# ========================
def build_ui():
    global root, canvas, lbl_title, lbl_stats, lbl_info, lbl_status
    global theme_btns, all_widgets
    
    root = tk.Tk()
    root.title("🗳️ 模拟投票/调查系统")
    root.geometry(f"{WIDTH}x{HEIGHT}")
    root.resizable(False, False)
    
    # ====== 顶部 ======
    top = tk.Frame(root)
    top.pack(fill="x", pady=3)
    
    lbl_title = tk.Label(top, text="🗳️ 投票调查系统", font=("Comic Sans MS", 14, "bold"))
    lbl_title.pack(side="left", padx=10)
    
    lbl_stats = tk.Label(top, text="", font=("Comic Sans MS", 10))
    lbl_stats.pack(side="left", padx=10)
    
    btn_new = tk.Button(top, text="✨ 新建调查", font=("Comic Sans MS", 10, "bold"),
                         bg="#7B1FA2", fg="white", command=create_survey_dialog)
    btn_new.pack(side="right", padx=5)
    
    btn_vote = tk.Button(top, text="🗳️ 投票", font=("Comic Sans MS", 10, "bold"),
                          bg="#E91E63", fg="white",
                          command=lambda: vote_dialog(cur_survey) if cur_survey else log_msg("⚠️ 请先选择一个调查"))
    btn_vote.pack(side="right", padx=5)
    
    btn_save = tk.Button(top, text="💾 保存", font=("Comic Sans MS", 9), command=save_data)
    btn_save.pack(side="right", padx=3)
    
    btn_load = tk.Button(top, text="📂 加载", font=("Comic Sans MS", 9), command=load_data)
    btn_load.pack(side="right", padx=3)
    
    # ====== 主题栏 ======
    tf = tk.Frame(root)
    tf.pack(fill="x", pady=1)
    tk.Label(tf, text="🎨 ", font=("", 8)).pack(side="left", padx=3)
    for name in THEMES:
        btn = tk.Button(tf, text=name, font=("Comic Sans MS", 7, "bold"),
                         relief="raised", bd=1, padx=3,
                         command=lambda n=name: apply_theme(n))
        btn.pack(side="left", padx=1)
        theme_btns.append(btn)
    
    # ====== 信息栏 ======
    info_bar = tk.Frame(root)
    info_bar.pack(fill="x", pady=1)
    lbl_info = tk.Label(info_bar, text="点击「✨ 新建调查」开始，或查看下方预设调查", font=("Comic Sans MS", 10))
    lbl_info.pack(side="left", padx=10)
    
    # ====== 画布 ======
    canvas_frame = tk.Frame(root)
    canvas_frame.pack(fill="both", expand=True, padx=3, pady=2)
    
    canvas = tk.Canvas(canvas_frame, width=WIDTH-10, height=450, highlightthickness=0)
    canvas.pack(fill="both", expand=True)
    canvas.bind("<Button-1>", on_canvas_click)
    
    # ====== 底部 ======
    bottom = tk.Frame(root)
    bottom.pack(fill="x", side="bottom", pady=2)
    
    lbl_status = tk.Label(bottom, text="🚀 系统就绪", font=("Comic Sans MS", 9))
    lbl_status.pack(side="left", padx=10)
    
    tk.Label(bottom, text="💡 提示: 点击调查卡片进入 | 在卡片上点击「投」快速投票 | 饼图显示比例",
             font=("Comic Sans MS", 8)).pack(side="right", padx=10)
    
    all_widgets.extend([top, tf, info_bar, canvas_frame, bottom,
                        btn_new, btn_vote, btn_save, btn_load,
                        lbl_title, lbl_stats, lbl_info, lbl_status])

# ========================
# 更新统计
# ========================
def update_stats():
    total = len(surveys)
    votes = sum(s["total_votes"] for s in surveys)
    lbl_stats.config(text=f"📊 {total}个调查 | {votes}票")

# ========================
# 主循环
# ========================
def game_loop():
    update_stats()
    root.after(500, game_loop)

# ========================
# 启动
# ========================
def init():
    global cur_sid
    build_ui()
    apply_theme("🌸 樱花粉")
    
    # 加载预设
    load_templates()
    log_msg(f"📋 已加载 {len(surveys)} 个预设调查")
    log_msg("💡 点击卡片查看详情，或创建你自己的调查")
    
    draw_survey()

if __name__ == "__main__":
    root = None
    init()
    game_loop()
    root.mainloop()
