import tkinter as tk
import time
import threading

class StopwatchApp:
    def __init__(self, root):
        self.root = root
        self.root.title("014. 计时器")
        self.root.geometry("400x520")
        self.root.resizable(False, False)

        # 状态
        self.running = False
        self.paused = False
        self.mode = "stopwatch"  # stopwatch / countdown
        self.start_time = 0
        self.elapsed = 0
        self.laps = []

        self.build_ui()

    def build_ui(self):
        # ===== 标题 =====
        tk.Label(
            self.root, text="⏱️ 计时器",
            font=("微软雅黑", 18, "bold")
        ).pack(pady=10)

        # ===== 模式切换 =====
        mode_frame = tk.Frame(self.root)
        mode_frame.pack()

        self.mode_var = tk.StringVar(value="stopwatch")
        tk.Radiobutton(
            mode_frame, text="正计时", variable=self.mode_var,
            value="stopwatch", command=self.switch_mode
        ).pack(side=tk.LEFT, padx=10)
        tk.Radiobutton(
            mode_frame, text="倒计时", variable=self.mode_var,
            value="countdown", command=self.switch_mode
        ).pack(side=tk.LEFT, padx=10)

        # ===== 倒计时设置 =====
        self.set_frame = tk.Frame(self.root)
        self.set_frame.pack(pady=5)

        tk.Label(self.set_frame, text="设定时间：").pack(side=tk.LEFT)
        self.hour_spin = tk.Spinbox(self.set_frame, from_=0, to=23, width=3)
        self.hour_spin.pack(side=tk.LEFT, padx=2)
        tk.Label(self.set_frame, text="时").pack(side=tk.LEFT)
        self.min_spin = tk.Spinbox(self.set_frame, from_=0, to=59, width=3)
        self.min_spin.pack(side=tk.LEFT, padx=2)
        tk.Label(self.set_frame, text="分").pack(side=tk.LEFT)
        self.sec_spin = tk.Spinbox(self.set_frame, from_=0, to=59, width=3)
        self.sec_spin.pack(side=tk.LEFT, padx=2)
        tk.Label(self.set_frame, text="秒").pack(side=tk.LEFT)

        # ===== 时间显示 =====
        self.time_label = tk.Label(
            self.root, text="00:00.00",
            font=("Consolas", 40, "bold"), fg="#1565C0"
        )
        self.time_label.pack(pady=15)

        # ===== 进度条（倒计时用） =====
        self.progress = tk.Scale(
            self.root, from_=0, to=100, orient=tk.HORIZONTAL,
            length=300, sliderlength=0, troughcolor="#e0e0e0",
            activebackground="#1565C0", showvalue=False
        )
        self.progress.set(0)
        self.progress.pack(pady=5)

        # ===== 控制按钮 =====
        ctrl_frame = tk.Frame(self.root)
        ctrl_frame.pack(pady=10)

        self.start_btn = tk.Button(
            ctrl_frame, text="▶ 开始", width=10,
            bg="#4CAF50", fg="white", font=("微软雅黑", 10),
            command=self.start
        )
        self.start_btn.pack(side=tk.LEFT, padx=5)

        self.pause_btn = tk.Button(
            ctrl_frame, text="⏸ 暂停", width=10,
            bg="#FF9800", fg="white", font=("微软雅黑", 10),
            command=self.toggle_pause
        )
        self.pause_btn.pack(side=tk.LEFT, padx=5)

        self.lap_btn = tk.Button(
            ctrl_frame, text="🏁 计次", width=10,
            bg="#2196F3", fg="white", font=("微软雅黑", 10),
            command=self.lap
        )
        self.lap_btn.pack(side=tk.LEFT, padx=5)

        self.reset_btn = tk.Button(
            ctrl_frame, text="↺ 重置", width=10,
            bg="#f44336", fg="white", font=("微软雅黑", 10),
            command=self.reset
        )
        self.reset_btn.pack(side=tk.LEFT, padx=5)

        # ===== 计次列表 =====
        tk.Label(self.root, text="— 计次记录 —", font=("微软雅黑", 10)).pack()
        self.lap_list = tk.Listbox(self.root, width=35, height=6, font=("Consolas", 10))
        self.lap_list.pack(pady=5)

    def switch_mode(self):
        self.mode = self.mode_var.get()
        self.reset()
        if self.mode == "countdown":
            self.set_frame.pack(pady=5)
            self.progress.pack(pady=5)
        else:
            self.set_frame.pack_forget()
            self.progress.pack_forget()

    def format_time(self, ms):
        total_sec = int(ms / 1000)
        hours = total_sec // 3600
        minutes = (total_sec % 3600) // 60
        seconds = total_sec % 60
        centisec = (ms // 10) % 100
        if hours > 0:
            return f"{hours:02d}:{minutes:02d}:{seconds:02d}.{centisec:02d}"
        return f"{minutes:02d}:{seconds:02d}.{centisec:02d}"

    def start(self):
        if self.running:
            return
        self.running = True
        self.paused = False
        self.start_btn.config(state="disabled")
        self.pause_btn.config(text="⏸ 暂停")

        if self.mode == "countdown":
            h = int(self.hour_spin.get())
            m = int(self.min_spin.get())
            s = int(self.sec_spin.get())
            self.countdown_total = (h * 3600 + m * 60 + s) * 1000
            self.countdown_remaining = self.countdown_total
            self.set_frame.pack_forget()
            threading.Thread(target=self.run_countdown, daemon=True).start()
        else:
            self.elapsed = 0
            self.start_time = time.time() * 1000
            threading.Thread(target=self.run_stopwatch, daemon=True).start()

    def run_stopwatch(self):
        while self.running:
            if not self.paused:
                now = time.time() * 1000
                self.elapsed = int(now - self.start_time)
                self.root.after(0, lambda: self.time_label.config(
                    text=self.format_time(self.elapsed)
                ))
            time.sleep(0.05)

    def run_countdown(self):
        while self.running and self.countdown_remaining > 0:
            if not self.paused:
                self.countdown_remaining -= 50
                self.root.after(0, lambda: [
                    self.time_label.config(text=self.format_time(self.countdown_remaining)),
                    self.progress.set(100 - self.countdown_remaining / self.countdown_total * 100)
                ])
            time.sleep(0.05)

        if self.countdown_remaining <= 0:
            self.root.after(0, self.finish_countdown)

    def finish_countdown(self):
        self.running = False
        self.time_label.config(text="⏰ 时间到！")
        self.progress.set(100)
        self.start_btn.config(state="normal")
        # 弹窗提醒
        import winsound
        winsound.MessageBeep(winsound.MB_ICONEXCLAMATION)
        tk.messagebox.showinfo("计时器", "⏰ 倒计时结束！")

    def toggle_pause(self):
        if not self.running:
            return
        self.paused = not self.paused
        self.pause_btn.config(text="▶ 继续" if self.paused else "⏸ 暂停")

    def lap(self):
        if not self.running:
            return
        self.laps.append(self.elapsed if self.mode == "stopwatch" else self.countdown_remaining)
        idx = len(self.laps)
        if self.mode == "stopwatch":
            prev = self.laps[-2] if len(self.laps) > 1 else 0
            lap_time = self.elapsed - prev
            text = f"计次 {idx}: {self.format_time(self.elapsed)} (间隔: {self.format_time(lap_time)})"
        else:
            elapsed_total = self.countdown_total - self.countdown_remaining
            text = f"计次 {idx}: {self.format_time(elapsed_total)}"
        self.lap_list.insert(tk.END, text)
        self.lap_list.see(tk.END)

    def reset(self):
        self.running = False
        self.paused = False
        self.elapsed = 0
        self.laps.clear()
        self.lap_list.delete(0, tk.END)
        self.time_label.config(text="00:00.00")
        self.progress.set(0)
        self.start_btn.config(state="normal")
        self.pause_btn.config(text="⏸ 暂停")


if __name__ == "__main__":
    root = tk.Tk()
    app = StopwatchApp(root)
    root.mainloop()