import tkinter as tk
import random
import time

# ---------- 全局配置 ----------
WIDTH, HEIGHT = 700, 500
BG_COLOR = "#2b3a4a"
CIRCLE_COLOR = "#ff6b6b"
CIRCLE_RADIUS = 25
FONT_COLOR = "#ffffff"
DURATION = 30  # 训练时长（秒）

class ReactionTrainer:
    def __init__(self, root):
        self.root = root
        self.root.title("反应速度训练 · 点击圆点")
        self.root.geometry(f"{WIDTH+40}x{HEIGHT+120}")
        self.root.resizable(False, False)
        self.root.configure(bg="#1e2a36")

        # ---------- 游戏状态变量 ----------
        self.score = 0
        self.reaction_times = []        # 存储每次反应时间（毫秒）
        self.last_reaction = 0.0
        self.avg_reaction = 0.0
        self.circle_visible = False
        self.circle_pos = (0, 0)
        self.circle_appear_time = 0.0

        self.game_active = False
        self.start_time = 0.0
        self.remaining = DURATION

        # ---------- 界面组件 ----------
        # 顶部信息栏
        self.info_frame = tk.Frame(root, bg="#1e2a36")
        self.info_frame.pack(pady=10)

        self.score_label = tk.Label(
            self.info_frame, text="得分: 0", font=("Segoe UI", 20, "bold"),
            fg="#b7e4ff", bg="#1e2a36"
        )
        self.score_label.grid(row=0, column=0, padx=20)

        self.react_label = tk.Label(
            self.info_frame, text="上次: -- ms", font=("Segoe UI", 16),
            fg="#c5f0c5", bg="#1e2a36"
        )
        self.react_label.grid(row=0, column=1, padx=20)

        self.avg_label = tk.Label(
            self.info_frame, text="平均: -- ms", font=("Segoe UI", 16),
            fg="#f0e68c", bg="#1e2a36"
        )
        self.avg_label.grid(row=0, column=2, padx=20)

        self.time_label = tk.Label(
            self.info_frame, text=f"剩余: {DURATION}s", font=("Segoe UI", 18, "bold"),
            fg="#ffb3b3", bg="#1e2a36"
        )
        self.time_label.grid(row=0, column=3, padx=20)

        # Canvas 绘图区域
        self.canvas = tk.Canvas(
            root, width=WIDTH, height=HEIGHT,
            bg=BG_COLOR, highlightthickness=0,
            cursor="crosshair"
        )
        self.canvas.pack(pady=10)

        # 底部按钮
        self.btn_frame = tk.Frame(root, bg="#1e2a36")
        self.btn_frame.pack(pady=10)

        self.start_btn = tk.Button(
            self.btn_frame, text="开始", font=("Segoe UI", 14, "bold"),
            bg="#4a6a8a", fg="white", width=10, height=1,
            command=self.start_game
        )
        self.start_btn.grid(row=0, column=0, padx=15)

        self.reset_btn = tk.Button(
            self.btn_frame, text="重置", font=("Segoe UI", 14, "bold"),
            bg="#8a5a5a", fg="white", width=10, height=1,
            command=self.reset_game
        )
        self.reset_btn.grid(row=0, column=1, padx=15)

        # 绑定鼠标点击事件
        self.canvas.bind("<Button-1>", self.on_click)

        # 初始化显示
        self.update_display()

        # 定时器更新（每秒刷新倒计时）
        self.update_timer()

    # ---------- 核心方法 ----------
    def spawn_circle(self):
        """在画布内随机生成圆点位置（保证完全可见）"""
        x = random.randint(CIRCLE_RADIUS, WIDTH - CIRCLE_RADIUS)
        y = random.randint(CIRCLE_RADIUS, HEIGHT - CIRCLE_RADIUS)
        return (x, y)

    def draw_circle(self, pos):
        """在画布上绘制圆点"""
        x, y = pos
        r = CIRCLE_RADIUS
        return self.canvas.create_oval(
            x - r, y - r, x + r, y + r,
            fill=CIRCLE_COLOR, outline="#ff9999", width=2
        )

    def clear_circle(self):
        """删除画布上的圆点"""
        self.canvas.delete("circle")

    def start_game(self):
        """开始新的训练"""
        if self.game_active:
            return
        # 重置数据（保留界面状态）
        self.reset_game_data()
        self.game_active = True
        self.start_time = time.time()
        self.remaining = DURATION

        # 生成第一个圆点
        self.circle_pos = self.spawn_circle()
        self.circle_visible = True
        self.circle_appear_time = time.time()
        self.clear_circle()
        self.draw_circle(self.circle_pos)

        # 更新按钮状态
        self.start_btn.config(state="disabled")
        self.update_display()

    def reset_game(self):
        """完全重置（停止训练，清空所有数据）"""
        self.game_active = False
        self.reset_game_data()
        self.clear_circle()
        self.circle_visible = False
        self.start_btn.config(state="normal")
        self.update_display()

    def reset_game_data(self):
        """重置成绩数据（不改变游戏激活状态）"""
        self.score = 0
        self.reaction_times = []
        self.last_reaction = 0.0
        self.avg_reaction = 0.0
        self.remaining = DURATION
        self.update_display()

    def on_click(self, event):
        """鼠标点击事件处理"""
        if not self.game_active or not self.circle_visible:
            return

        x, y = event.x, event.y
        cx, cy = self.circle_pos
        # 检测是否点击到圆点（距离判断）
        dist = ((x - cx) ** 2 + (y - cy) ** 2) ** 0.5
        if dist <= CIRCLE_RADIUS:
            # 得分
            self.score += 1
            # 计算反应时间（毫秒）
            now = time.time()
            react_ms = (now - self.circle_appear_time) * 1000
            self.reaction_times.append(react_ms)
            self.last_reaction = react_ms
            if self.reaction_times:
                self.avg_reaction = sum(self.reaction_times) / len(self.reaction_times)

            # 生成新圆点
            self.circle_pos = self.spawn_circle()
            self.circle_appear_time = now
            self.clear_circle()
            self.draw_circle(self.circle_pos)

            # 更新显示
            self.update_display()

    def update_display(self):
        """更新所有标签显示"""
        self.score_label.config(text=f"得分: {self.score}")
        if self.last_reaction > 0:
            self.react_label.config(text=f"上次: {self.last_reaction:.0f} ms")
        else:
            self.react_label.config(text="上次: -- ms")

        if self.reaction_times:
            self.avg_label.config(text=f"平均: {self.avg_reaction:.0f} ms")
        else:
            self.avg_label.config(text="平均: -- ms")

        self.time_label.config(text=f"剩余: {max(0, int(self.remaining))}s")

    def update_timer(self):
        """每秒更新倒计时，并检查是否超时"""
        if self.game_active:
            elapsed = time.time() - self.start_time
            self.remaining = DURATION - elapsed
            if self.remaining <= 0:
                # 训练结束
                self.game_active = False
                self.remaining = 0
                self.clear_circle()
                self.circle_visible = False
                self.start_btn.config(state="normal")
                # 显示结束信息（在画布上）
                self.canvas.create_text(
                    WIDTH//2, HEIGHT//2 - 20,
                    text="训练结束！", font=("Segoe UI", 28, "bold"),
                    fill="#ffffff", tags="end_msg"
                )
                if self.reaction_times:
                    avg = sum(self.reaction_times) / len(self.reaction_times)
                    self.canvas.create_text(
                        WIDTH//2, HEIGHT//2 + 40,
                        text=f"平均反应: {avg:.0f} ms  总点击: {self.score}",
                        font=("Segoe UI", 20), fill="#dddddd", tags="end_msg"
                    )
                self.update_display()
            else:
                # 更新倒计时显示
                self.update_display()
                # 如果剩余时间小于等于0，上面已经处理，否则继续
        # 每1000ms调用一次
        self.root.after(1000, self.update_timer)

# ---------- 启动程序 ----------
if __name__ == "__main__":
    root = tk.Tk()
    app = ReactionTrainer(root)
    root.mainloop()