import tkinter as tk
from tkinter import messagebox, simpledialog
import random
import math
import time
import json
import os

# ============ 配置文件路径 ============
CONFIG_FILE = os.path.join(os.path.dirname(__file__), "wheel_config.json")

# ============ 默认奖品配置 ============
DEFAULT_PRIZES = [
    {"name": "🎉 一等奖 iPhone", "color": "#FF6B6B", "weight": 1},
    {"name": "🎁 二等奖 平板",   "color": "#FFA07A", "weight": 2},
    {"name": "🏆 三等奖 耳机",   "color": "#FFD93D", "weight": 3},
    {"name": "☕ 四等奖 咖啡券", "color": "#6BCB77", "weight": 5},
    {"name": "🍀 五等奖 绿植",   "color": "#4D96FF", "weight": 5},
    {"name": "😢 谢谢参与",      "color": "#9B59B6", "weight": 10},
    {"name": "🎮 六等奖 游戏手柄","color": "#E056A0", "weight": 4},
    {"name": "📚 七等奖 书籍",   "color": "#00CEC9", "weight": 5},
]

# ============ 默认设置 ============
DEFAULT_SETTINGS = {
    "bg_color": "#1A1A2E",
    "text_color": "#FFFFFF",
    "pointer_color": "#FFDD57",
    "spin_duration": 4.0,     # 旋转秒数
    "min_spins": 5,           # 最少旋转圈数
    "max_spins": 8,           # 最多旋转圈数
}


class WheelGame:
    """转盘抽奖主类"""

    def __init__(self, root):
        self.root = root
        self.root.title("🎡 转盘抽奖小游戏")
        self.root.geometry("900x750")
        self.root.resizable(False, False)
        self.root.configure(bg=DEFAULT_SETTINGS["bg_color"])

        # ---- 加载配置 ----
        self.prizes = self._load_prizes()
        self.settings = DEFAULT_SETTINGS.copy()

        # ---- 状态变量 ----
        self.angle = 0.0          # 当前转盘角度
        self.is_spinning = False  # 是否正在旋转
        self.history = []         # 中奖记录
        self.animation_id = None  # 动画任务ID

        # ---- 构建界面 ----
        self._build_ui()

        # ---- 绘制初始转盘 ----
        self.draw_wheel()

    # ==================== 配置管理 ====================
    def _load_prizes(self):
        """从文件加载奖品，失败则用默认"""
        try:
            if os.path.exists(CONFIG_FILE):
                with open(CONFIG_FILE, "r", encoding="utf-8") as f:
                    data = json.load(f)
                    if isinstance(data, list) and len(data) > 1:
                        return data
        except Exception:
            pass
        return [p.copy() for p in DEFAULT_PRIZES]

    def _save_prizes(self):
        """保存奖品到文件"""
        try:
            with open(CONFIG_FILE, "w", encoding="utf-8") as f:
                json.dump(self.prizes, f, ensure_ascii=False, indent=2)
        except Exception as e:
            messagebox.showerror("保存失败", f"无法保存配置：{e}")

    # ==================== 界面构建 ====================
    def _build_ui(self):
        """构建完整用户界面"""
        bg = DEFAULT_SETTINGS["bg_color"]
        fg = DEFAULT_SETTINGS["text_color"]

        # ---- 顶部标题 ----
        title_frame = tk.Frame(self.root, bg=bg)
        title_frame.pack(pady=(18, 8))

        tk.Label(
            title_frame, text="🎡 幸运转盘抽奖", font=("WenQuanYi Micro Hei", 26, "bold"),
            fg="#FFDD57", bg=bg
        ).pack()

        tk.Label(
            title_frame, text="点击「开始抽奖」转动转盘，看看今天的好运！",
            font=("WenQuanYi Micro Hei", 12), fg="#AAAAAA", bg=bg
        ).pack(pady=(4, 0))

        # ---- 中间区域：转盘 + 侧边栏 ----
        main_frame = tk.Frame(self.root, bg=bg)
        main_frame.pack(pady=10)

        # 左侧：Canvas 转盘
        self.canvas_size = 420
        self.canvas = tk.Canvas(
            main_frame, width=self.canvas_size, height=self.canvas_size,
            bg=bg, highlightthickness=0
        )
        self.canvas.pack(side=tk.LEFT, padx=(30, 20))

        # 右侧：控制面板
        ctrl = tk.Frame(main_frame, bg=bg, width=260)
        ctrl.pack(side=tk.LEFT, fill=tk.Y, padx=(10, 30))
        ctrl.pack_propagate(False)

        tk.Label(ctrl, text="🎮 控制台", font=("WenQuanYi Micro Hei", 16, "bold"),
                 fg="#FFDD57", bg=bg).pack(pady=(0, 12))

        # 抽奖按钮
        self.spin_btn = tk.Button(
            ctrl, text="🎯 开始抽奖", font=("WenQuanYi Micro Hei", 16, "bold"),
            bg="#FF6B6B", fg="white", activebackground="#FF5252",
            relief=tk.FLAT, cursor="hand2", pady=10,
            command=self.start_spin
        )
        self.spin_btn.pack(fill=tk.X, pady=6, ipady=4)

        # 设置按钮
        tk.Button(
            ctrl, text="⚙️ 编辑奖品", font=("WenQuanYi Micro Hei", 13),
            bg="#4D96FF", fg="white", activebackground="#3A7BD5",
            relief=tk.FLAT, cursor="hand2", pady=6,
            command=self.open_prize_editor
        ).pack(fill=tk.X, pady=4)

        # 重置记录
        tk.Button(
            ctrl, text="🗑️ 清空记录", font=("WenQuanYi Micro Hei", 13),
            bg="#636E72", fg="white", activebackground="#4A5458",
            relief=tk.FLAT, cursor="hand2", pady=6,
            command=self.clear_history
        ).pack(fill=tk.X, pady=4)

        # 中奖概率显示
        prob_frame = tk.LabelFrame(
            ctrl, text="中奖概率", font=("WenQuanYi Micro Hei", 11),
            fg="#AAAAAA", bg="#16213E", labelanchor="n"
        )
        prob_frame.pack(fill=tk.BOTH, expand=True, pady=(12, 0))

        self.prob_text = tk.Text(
            prob_frame, height=10, font=("WenQuanYi Micro Hei", 10),
            bg="#16213E", fg=fg, relief=tk.FLAT, state=tk.DISABLED,
            wrap=tk.NONE
        )
        self.prob_text.pack(fill=tk.BOTH, expand=True, padx=6, pady=6)
        self._refresh_probability()

        # ---- 底部：中奖记录 ----
        bottom = tk.Frame(self.root, bg=bg)
        bottom.pack(fill=tk.X, padx=30, pady=(10, 0))

        tk.Label(bottom, text="📋 中奖记录", font=("WenQuanYi Micro Hei", 13, "bold"),
                 fg="#FFDD57", bg=bg).pack(anchor=tk.W)

        self.history_var = tk.StringVar(value="暂无抽奖记录")
        tk.Label(
            bottom, textvariable=self.history_var,
            font=("WenQuanYi Micro Hei", 11), fg="#CCCCCC", bg="#16213E",
            anchor=tk.W, justify=tk.LEFT,
            relief=tk.SUNKEN, padx=10, pady=6
        ).pack(fill=tk.X, pady=(4, 0))

        # ---- 状态栏 ----
        self.status_var = tk.StringVar(value="就绪")
        tk.Label(
            self.root, textvariable=self.status_var,
            font=("WenQuanYi Micro Hei", 10), fg="#666666", bg=bg
        ).pack(side=tk.BOTTOM, pady=4)

    # ==================== 转盘绘制 ====================
    def draw_wheel(self):
        """绘制转盘（静态）"""
        self.canvas.delete("all")
        n = len(self.prizes)
        if n == 0:
            return

        cx = cy = self.canvas_size / 2
        r = self.canvas_size / 2 - 10
        slice_angle = 360.0 / n

        # 外圈装饰
        self.canvas.create_oval(
            cx - r - 6, cy - r - 6, cx + r + 6, cy + r + 6,
            outline="#FFDD57", width=4, fill=""
        )

        # 扇区
        for i, prize in enumerate(self.prizes):
            start_angle = self.angle + i * slice_angle
            end_angle = start_angle + slice_angle

            # 绘制扇形（用 create_arc 的 pieslice 模式）
            self.canvas.create_arc(
                cx - r, cy - r, cx + r, cy + r,
                start=start_angle, extent=slice_angle,
                fill=prize["color"], outline="#FFFFFF", width=2,
                style=tk.PIESLICE
            )

            # 文字
            mid_angle = math.radians(start_angle + slice_angle / 2)
            text_r = r * 0.62
            tx = cx + text_r * math.cos(mid_angle)
            ty = cy - text_r * math.sin(mid_angle)

            # 根据亮度决定文字颜色
            text_color = self._contrast_color(prize["color"])
            short_name = prize["name"]
            if len(short_name) > 6:
                short_name = short_name[:5] + "…"

            self.canvas.create_text(
                tx, ty, text=short_name,
                font=("WenQuanYi Micro Hei", 12, "bold"),
                fill=text_color, angle=0
            )

        # 中心圆
        inner_r = 28
        self.canvas.create_oval(
            cx - inner_r, cy - inner_r, cx + inner_r, cy + inner_r,
            fill="#1A1A2E", outline="#FFDD57", width=3
        )
        self.canvas.create_text(
            cx, cy, text="GO", font=("WenQuanYi Micro Hei", 14, "bold"),
            fill="#FFDD57"
        )

        # 指针（三角形在顶部）
        ptr_h = 30
        ptr_w = 18
        self.canvas.create_polygon(
            cx, cy - r - 6,
            cx - ptr_w, cy - r + ptr_h - 6,
            cx + ptr_w, cy - r + ptr_h - 6,
            fill=DEFAULT_SETTINGS["pointer_color"], outline="#FFFFFF", width=2
        )

    def _contrast_color(self, hex_color):
        """根据背景色亮度返回黑/白文字色"""
        hex_color = hex_color.lstrip("#")
        r, g, b = int(hex_color[:2], 16), int(hex_color[2:4], 16), int(hex_color[4:6], 16)
        luminance = 0.299 * r + 0.587 * g + 0.114 * b
        return "#1A1A2E" if luminance > 140 else "#FFFFFF"

    # ==================== 抽奖逻辑 ====================
    def start_spin(self):
        """开始旋转"""
        if self.is_spinning:
            return
        if len(self.prizes) < 2:
            messagebox.showwarning("提示", "请至少设置 2 个奖品！")
            return

        self.is_spinning = True
        self.spin_btn.config(state=tk.DISABLED, text="🌀 抽奖中…")
        self.status_var.set("转盘旋转中…")

        # 加权随机选择目标
        weights = [p["weight"] for p in self.prizes]
        target_idx = random.choices(range(len(self.prizes)), weights=weights, k=1)[0]

        n = len(self.prizes)
        slice_angle = 360.0 / n

        # 目标扇区中心角度（以指针在顶部 0° 为参考）
        # 当前转盘 self.angle 是整体偏移，扇区 i 的范围：
        #   [self.angle + i*slice, self.angle + (i+1)*slice]
        # 指针固定在顶部（对应画布 0° = 12 点钟方向即 -90° 需校正）
        # 简化处理：让目标扇区中心对齐指针位置
        target_center = target_idx * slice_angle + slice_angle / 2  # 在转盘本地坐标
        # 指针在顶部 = 画布 0° 方向；要让 target_center 转到指针处：
        # angle_final + target_center = 0 (mod 360)  => angle_final = -target_center
        # 加上额外整圈
        extra_spins = random.randint(self.settings["min_spins"], self.settings["max_spins"])
        target_angle = -target_center + 360 * extra_spins
        # 确保是正向旋转（角度增加）
        if target_angle < self.angle + 360:
            target_angle += 360 * 2

        # 动画参数
        self.spin_target = target_angle
        self.spin_start_angle = self.angle
        self.spin_elapsed = 0.0
        self.spin_duration = self.settings["spin_duration"]
        self.spin_target_idx = target_idx

        self._animate_spin()

    def _animate_spin(self):
        """旋转动画（使用 ease-out 缓动）"""
        dt = 0.03  # 每帧约 30ms
        self.spin_elapsed += dt
        t = min(self.spin_elapsed / self.spin_duration, 1.0)

        # easeOutCubic 缓动
        ease = 1 - (1 - t) ** 3
        current = self.spin_start_angle + (self.spin_target - self.spin_start_angle) * ease
        self.angle = current % 360

        self.draw_wheel()

        if t < 1.0:
            self.animation_id = self.root.after(30, self._animate_spin)
        else:
            self.angle = self.spin_target % 360
            self.is_spinning = False
            self.spin_btn.config(state=tk.NORMAL, text="🎯 开始抽奖")
            self._on_spin_finish(self.spin_target_idx)

    def _on_spin_finish(self, idx):
        """旋转结束处理"""
        prize = self.prizes[idx]
        self.history.append(prize["name"])

        # 更新记录显示
        recent = self.history[-5:]
        self.history_var.set(" → ".join(reversed(recent)))

        self.status_var.set(f"🎊 恭喜抽中：{prize['name']}")

        # 弹窗
        messagebox.showinfo(
            "🎉 抽奖结果",
            f"恭喜你抽中了：\n\n  {prize['name']}\n\n祝你好运连连！🍀"
        )

    # ==================== 奖品编辑 ====================
    def open_prize_editor(self):
        """打开奖品编辑窗口"""
        editor = tk.Toplevel(self.root)
        editor.title("⚙️ 编辑奖品")
        editor.geometry("560x560")
        editor.configure(bg=DEFAULT_SETTINGS["bg_color"])
        editor.transient(self.root)
        editor.grab_set()

        bg = DEFAULT_SETTINGS["bg_color"]
        fg = DEFAULT_SETTINGS["text_color"]

        tk.Label(editor, text="奖品名称", font=("WenQuanYi Micro Hei", 11, "bold"),
                 fg=fg, bg=bg).grid(row=0, column=0, padx=8, pady=(12, 4), sticky=tk.W)
        tk.Label(editor, text="颜色", font=("WenQuanYi Micro Hei", 11, "bold"),
                 fg=fg, bg=bg).grid(row=0, column=1, padx=8, pady=(12, 4), sticky=tk.W)
        tk.Label(editor, text="权重", font=("WenQuanYi Micro Hei", 11, "bold"),
                 fg=fg, bg=bg).grid(row=0, column=2, padx=8, pady=(12, 4), sticky=tk.W)

        rows = []
        for i, p in enumerate(self.prizes):
            name_var = tk.StringVar(value=p["name"])
            color_var = tk.StringVar(value=p["color"])
            weight_var = tk.IntVar(value=p["weight"])

            r = i + 1
            e_name = tk.Entry(editor, textvariable=name_var, width=26, font=("WenQuanYi Micro Hei", 11))
            e_name.grid(row=r, column=0, padx=8, pady=3)
            e_color = tk.Entry(editor, textvariable=color_var, width=12, font=("WenQuanYi Micro Hei", 11))
            e_color.grid(row=r, column=1, padx=8, pady=3)
            e_weight = tk.Entry(editor, textvariable=weight_var, width=6, font=("WenQuanYi Micro Hei", 11))
            e_weight.grid(row=r, column=2, padx=8, pady=3)

            # 颜色预览方块
            preview = tk.Label(editor, width=4, bg=p["color"], relief=tk.RIDGE)
            preview.grid(row=r, column=3, padx=(0, 8), pady=3)

            rows.append((name_var, color_var, weight_var, preview))

        def update_preview(idx):
            try:
                color = rows[idx][2].get() if False else rows[idx][1].get()
                rows[idx][3].config(bg=color)
            except Exception:
                pass

        for idx, (nv, cv, wv, pv) in enumerate(rows):
            cv.trace_add("write", lambda *a, i=idx: rows[i][3].config(bg=rows[i][1].get()))

        btn_frame = tk.Frame(editor, bg=bg)
        btn_frame.grid(row=len(self.prizes) + 1, column=0, columnspan=4, pady=16)

        def save_and_close():
            new_prizes = []
            for nv, cv, wv, pv in rows:
                name = nv.get().strip()
                color = cv.get().strip()
                try:
                    weight = int(wv.get())
                except ValueError:
                    weight = 1
                if name and color:
                    new_prizes.append({"name": name, "color": color, "weight": max(1, weight)})
            if len(new_prizes) < 2:
                messagebox.showerror("错误", "至少需要 2 个奖品！", parent=editor)
                return
            self.prizes = new_prizes
            self._save_prizes()
            self.angle = 0
            self.draw_wheel()
            self._refresh_probability()
            editor.destroy()
            self.status_var.set("奖品已更新")

        tk.Button(btn_frame, text="✅ 保存", font=("WenQuanYi Micro Hei", 13, "bold"),
                  bg="#6BCB77", fg="white", relief=tk.FLAT, padx=24, pady=6,
                  command=save_and_close).pack(side=tk.LEFT, padx=8)

        tk.Button(btn_frame, text="🔄 恢复默认", font=("WenQuanYi Micro Hei", 12),
                  bg="#E17055", fg="white", relief=tk.FLAT, padx=16, pady=6,
                  command=lambda: self._reset_prizes(editor)).pack(side=tk.LEFT, padx=8)

        tk.Button(btn_frame, text="❌ 取消", font=("WenQuanYi Micro Hei", 12),
                  bg="#636E72", fg="white", relief=tk.FLAT, padx=16, pady=6,
                  command=editor.destroy).pack(side=tk.LEFT, padx=8)

        # 提示
        tk.Label(
            editor, text="💡 提示：颜色用十六进制如 #FF6B6B，权重越大概率越高",
            font=("WenQuanYi Micro Hei", 10), fg="#888888", bg=bg
        ).grid(row=len(self.prizes) + 2, column=0, columnspan=4, pady=(4, 0))

    def _reset_prizes(self, editor):
        if messagebox.askyesno("确认", "恢复默认奖品列表？", parent=editor):
            self.prizes = [p.copy() for p in DEFAULT_PRIZES]
            self._save_prizes()
            editor.destroy()
            self.angle = 0
            self.draw_wheel()
            self._refresh_probability()
            self.status_var.set("已恢复默认奖品")

    def clear_history(self):
        if self.is_spinning:
            return
        self.history = []
        self.history_var.set("暂无抽奖记录")
        self.status_var.set("记录已清空")

    # ==================== 概率刷新 ====================
    def _refresh_probability(self):
        total = sum(p["weight"] for p in self.prizes)
        self.prob_text.config(state=tk.NORMAL)
        self.prob_text.delete("1.0", tk.END)
        for p in self.prizes:
            prob = p["weight"] / total * 100
            self.prob_text.insert(tk.END, f"{p['name']}\n  → {prob:.1f}%\n\n")
        self.prob_text.config(state=tk.DISABLED)


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