import pygame
import sys
import math
import time as pytime

# ── 初始化 ──────────────────────────────────────
pygame.init()
WIDTH, HEIGHT = 560, 420
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("013. 定时器")
clock = pygame.time.Clock()

# ── 颜色 ─────────────────────────────────────────
WHITE   = (255, 255, 255)
BLACK   = (0, 0, 0)
RED     = (220, 50, 50)
GREEN   = (50, 200, 80)
BLUE    = (60, 120, 220)
GRAY    = (180, 180, 185)
DARK    = (25, 25, 35)
YELLOW  = (255, 220, 50)
ORANGE  = (255, 160, 20)

# ── 点阵数字 ─────────────────────────────────────
DIGITS_MAP = {
    '0': [0b01110, 0b10001, 0b10011, 0b10101, 0b11001, 0b10001, 0b01110],
    '1': [0b00100, 0b01100, 0b00100, 0b00100, 0b00100, 0b00100, 0b01110],
    '2': [0b01110, 0b10001, 0b00001, 0b00010, 0b00100, 0b01000, 0b11111],
    '3': [0b01110, 0b10001, 0b00001, 0b00110, 0b00001, 0b10001, 0b01110],
    '4': [0b00010, 0b00110, 0b01010, 0b10010, 0b11111, 0b00010, 0b00010],
    '5': [0b11111, 0b10000, 0b11110, 0b00001, 0b00001, 0b10001, 0b01110],
    '6': [0b00110, 0b01000, 0b10000, 0b11110, 0b10001, 0b10001, 0b01110],
    '7': [0b11111, 0b00001, 0b00010, 0b00100, 0b01000, 0b01000, 0b01000],
    '8': [0b01110, 0b10001, 0b10001, 0b01110, 0b10001, 0b10001, 0b01110],
    '9': [0b01110, 0b10001, 0b10001, 0b01111, 0b00001, 0b00010, 0b01100],
    ':': [0b00000, 0b00100, 0b00000, 0b00000, 0b00000, 0b00100, 0b00000],
    '.': [0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00000, 0b00100],
}

def make_text(text, size=40, color=WHITE):
    text = str(text)
    scale = size // 8
    char_w = 5 * scale
    char_h = 7 * scale
    gap = 2
    total_w = len(text) * (char_w + gap)
    img = pygame.Surface((total_w, char_h), pygame.SRCALPHA)
    for idx, ch in enumerate(text):
        pat = DIGITS_MAP.get(ch, DIGITS_MAP['0'])
        for row in range(7):
            bits = pat[row]
            for col in range(5):
                if bits & (1 << (4 - col)):
                    px = idx * (char_w + gap) + col * scale
                    py = row * scale
                    for dx in range(scale):
                        for dy in range(scale):
                            if 0 <= px+dx < total_w and 0 <= py+dy < char_h:
                                img.set_at((px+dx, py+dy), color)
    return img

def draw_button(surf, text, x, y, w, h, color, text_color=WHITE, border=2, radius=8):
    pygame.draw.rect(surf, color, (x, y, w, h), border_radius=radius)
    pygame.draw.rect(surf, WHITE, (x, y, w, h), border, border_radius=radius)
    txt = make_text(text, 20, text_color)
    surf.blit(txt, (x + w//2 - txt.get_width()//2, y + h//2 - txt.get_height()//2))

# ════════════════════════════════════════════════
# 定时器核心
# ════════════════════════════════════════════════
MODE_STOPWATCH = 0  # 秒表
MODE_COUNTDOWN = 1  # 倒计时
MODE_TIMER     = 2  # 正计时（设定目标时间）

class Timer:
    def __init__(self):
        self.mode = MODE_STOPWATCH
        self.running = False
        self.paused = False
        
        # 秒表
        self.stopwatch_ms = 0
        
        # 倒计时
        self.countdown_total = 60 * 1000   # 默认1分钟
        self.countdown_left = self.countdown_total
        
        # 正计时
        self.timer_target = 5 * 60 * 1000  # 默认5分钟
        self.timer_elapsed = 0
        
        self.last_tick = pytime.time()
        self.input_value = 1  # 分钟数（用于调整）
        
        # 完成标志
        self.completed = False
        self.complete_time = 0

    def fmt(self, ms):
        """格式化时间为 MM:SS 或 HH:MM:SS"""
        total_sec = max(0, ms // 1000)
        hours = total_sec // 3600
        minutes = (total_sec % 3600) // 60
        seconds = total_sec % 60
        if hours > 0:
            return f"{hours:02d}:{minutes:02d}:{seconds:02d}"
        return f"{minutes:02d}:{seconds:02d}"

    def fmt_precise(self, ms):
        """精确到毫秒的格式 MM:SS.ms"""
        total_sec = max(0, ms // 1000)
        minutes = total_sec // 60
        seconds = total_sec % 60
        centiseconds = (ms % 1000) // 10
        return f"{minutes:02d}:{seconds:02d}.{centiseconds:02d}"

    def get_display_time(self):
        if self.mode == MODE_STOPWATCH:
            return self.fmt_precise(self.stopwatch_ms)
        elif self.mode == MODE_COUNTDOWN:
            return self.fmt(self.countdown_left)
        else:  # 正计时
            remaining = max(0, self.timer_target - self.timer_elapsed)
            return self.fmt(remaining)

    def get_progress(self):
        """返回进度 0.0 ~ 1.0"""
        if self.mode == MODE_STOPWATCH:
            return min(1.0, self.stopwatch_ms / (3600 * 1000))
        elif self.mode == MODE_COUNTDOWN:
            total = self.countdown_total
            left = self.countdown_left
            return 1.0 - (left / total) if total > 0 else 0
        else:
            return min(1.0, self.timer_elapsed / self.timer_target) if self.timer_target > 0 else 0

    def reset(self):
        self.running = False
        self.paused = False
        self.completed = False
        self.stopwatch_ms = 0
        self.countdown_left = self.countdown_total
        self.timer_elapsed = 0

    def toggle(self):
        if not self.running:
            self.running = True
            self.paused = False
            self.completed = False
            self.last_tick = pytime.time()
        else:
            self.paused = not self.paused
            if not self.paused:
                self.last_tick = pytime.time()

    def update(self):
        if not self.running or self.paused:
            return
        
        now = pytime.time()
        dt = int((now - self.last_tick) * 1000)
        self.last_tick = now
        
        if self.mode == MODE_STOPWATCH:
            self.stopwatch_ms += dt
            
        elif self.mode == MODE_COUNTDOWN:
            self.countdown_left = max(0, self.countdown_left - dt)
            if self.countdown_left <= 0 and not self.completed:
                self.completed = True
                self.complete_time = 60
                self.running = False
                
        else:  # 正计时
            self.timer_elapsed += dt
            if self.timer_elapsed >= self.timer_target and not self.completed:
                self.completed = True
                self.complete_time = 60
                self.running = False
        
        if self.complete_time > 0:
            self.complete_time -= 1

    def set_input(self, value):
        """设置输入值（分钟）"""
        self.input_value = max(1, min(999, value))
        self.countdown_total = self.input_value * 60 * 1000
        self.countdown_left = self.countdown_total
        self.timer_target = self.input_value * 60 * 1000

    def draw(self, surf):
        surf.fill(DARK)
        
        # ── 标题 ──
        titles = {MODE_STOPWATCH: "秒表", MODE_COUNTDOWN: "倒计时", MODE_TIMER: "正计时"}
        title = make_text(titles[self.mode], 26, BLUE)
        surf.blit(title, (WIDTH//2 - title.get_width()//2, 16))
        
        # ── 时间显示 ──
        time_str = self.get_display_time()
        
        # 完成时闪烁红色
        if self.completed and self.complete_time % 8 < 4:
            display_color = RED
        elif self.mode == MODE_COUNTDOWN and self.countdown_left < 10000 and self.running:
            display_color = ORANGE
        else:
            display_color = WHITE
        
        time_size = 72 if len(time_str) <= 8 else 56
        time_img = make_text(time_str, time_size, display_color)
        tx = WIDTH//2 - time_img.get_width()//2
        ty = 70
        surf.blit(time_img, (tx, ty))
        
        # ── 进度条 ──
        progress = self.get_progress()
        bar_x, bar_y = 40, ty + time_img.get_height() + 20
        bar_w, bar_h = WIDTH - 80, 12
        # 背景
        pygame.draw.rect(surf, (50, 50, 60), (bar_x, bar_y, bar_w, bar_h), border_radius=6)
        # 进度
        prog_w = int(bar_w * progress)
        if prog_w > 0:
            prog_color = GREEN if progress < 0.8 else (ORANGE if progress < 0.95 else RED)
            pygame.draw.rect(surf, prog_color, (bar_x, bar_y, prog_w, bar_h), border_radius=6)
        # 边框
        pygame.draw.rect(surf, GRAY, (bar_x, bar_y, bar_w, bar_h), 1, border_radius=6)
        
        # 百分比
        pct = make_text(f"{int(progress * 100)}%", 16, GRAY)
        surf.blit(pct, (WIDTH//2 - pct.get_width()//2, bar_y + bar_h + 6))
        
        # ── 状态 ──
        if self.completed:
            status = "✓ 时间到!" if self.mode != MODE_STOPWATCH else ""
        elif self.running and not self.paused:
            status = "● 运行中"
        elif self.paused:
            status = "‖ 已暂停"
        else:
            status = "■ 已停止"
        
        if status:
            st = make_text(status, 18, GRAY)
            surf.blit(st, (WIDTH//2 - st.get_width()//2, bar_y + bar_h + 30))
        
        # ── 模式切换按钮 ──
        modes = ["秒表", "倒计时", "正计时"]
        btn_y_top = 10
        for i, m in enumerate(modes):
            bx = 20 + i * 174
            bw = 164; bh = 32
            c = [GREEN, BLUE, ORANGE][i]
            draw_button(surf, m, bx, btn_y_top, bw, bh, c, border=3 if i == self.mode else 2)
        
        # ── 控制按钮 ──
        btn_y = HEIGHT - 70
        
        # 开始/暂停
        label = "开始" if not self.running else ("继续" if self.paused else "暂停")
        draw_button(surf, label, 30, btn_y, 156, 44, GREEN)
        
        # 重置
        draw_button(surf, "重置", 208, btn_y, 144, 44, RED)
        
        # 退出
        draw_button(surf, "退出", 374, btn_y, 146, 44, (80, 80, 80))
        
        # ── 调整提示 ──
        if self.mode != MODE_STOPWATCH and not self.running:
            unit = "分钟"
            hint = make_text(f"← → 调整: {self.input_value} {unit}", 16, GRAY)
            surf.blit(hint, (WIDTH//2 - hint.get_width()//2, HEIGHT - 116))
            
            # 快捷预设
            presets = [1, 3, 5, 10, 15, 25, 30]
            preset_y = HEIGHT - 136
            for i, p in enumerate(presets):
                px = 30 + i * 73
                pw = 65; ph = 26
                active = (p == self.input_value)
                c = (80, 80, 100) if not active else (100, 100, 140)
                draw_button(surf, f"{p}m", px, preset_y, pw, ph, c, border=2 if active else 1)

# ════════════════════════════════════════════════
# 主循环
# ════════════════════════════════════════════════
def main():
    timer = Timer()
    presets = [1, 3, 5, 10, 15, 25, 30]
    
    while True:
        mx, my = pygame.mouse.get_pos()
        
        for e in pygame.event.get():
            if e.type == pygame.QUIT:
                pygame.quit(); sys.exit()
            
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_SPACE:
                    timer.toggle()
                elif e.key == pygame.K_r:
                    timer.reset()
                elif e.key == pygame.K_ESCAPE:
                    pygame.quit(); sys.exit()
                elif e.key == pygame.K_LEFT and timer.mode != MODE_STOPWATCH:
                    timer.set_input(timer.input_value - 1)
                elif e.key == pygame.K_RIGHT and timer.mode != MODE_STOPWATCH:
                    timer.set_input(timer.input_value + 1)
            
            if e.type == pygame.MOUSEBUTTONDOWN:
                # 模式切换
                for i in range(3):
                    bx = 20 + i * 174
                    if bx <= mx <= bx + 154 and 10 <= my <= 42:
                        timer.mode = i
                        timer.reset()
                        timer.set_input(timer.input_value)
                
                # 控制按钮
                btn_y = HEIGHT - 70
                if 30 <= mx <= 166 and btn_y <= my <= btn_y + 44:
                    timer.toggle()
                if 194 <= mx <= 338 and btn_y <= my <= btn_y + 44:
                    timer.reset()
                if 364 <= mx <= 510 and btn_y <= my <= btn_y + 44:
                    pygame.quit(); sys.exit()
                
                # 预设按钮
                if timer.mode != MODE_STOPWATCH and not timer.running:
                    preset_y = HEIGHT - 134
                    for i, p in enumerate(presets):
                        px = 30 + i * 71
                        if px <= mx <= px + 61 and preset_y <= my <= preset_y + 24:
                            timer.set_input(p)
        
        timer.update()
        timer.draw(screen)
        pygame.display.flip()
        clock.tick(60)

if __name__ == "__main__":
    main()