import pygame
import sys
import time
import random

pygame.init()
# 窗口
WIDTH, HEIGHT = 1000, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("打字练习")
clock = pygame.time.Clock()

# 字体
FONT = pygame.font.SysFont("Consolas", 20)
FONT_BIG = pygame.font.SysFont("Consolas", 28, bold=True)
SMALL = pygame.font.SysFont("Consolas", 16)

# 颜色
BG = (30, 34, 40)
PANEL = (22, 26, 30)
TEXT_COLOR = (230, 230, 230)
GOOD = (120, 200, 120)
BAD = (255, 120, 120)
CURSOR_COLOR = (200, 200, 60)
HINT = (160, 160, 160)
ACCENT = (100, 150, 230)

# 练习段落（可以从文件加载或扩充）
PARAGRAPHS = [
    "The quick brown fox jumps over the lazy dog.",
    "Typing practice helps increase your speed and accuracy.",
    "Python is a great programming language for beginners.",
    "练习中文可以提高输入效率并熟悉常用词组。",
    "Consistency and patience are keys to improvement."
]

# 模式配置
TIME_LIMIT = 60      # 限时（秒），设为 0 表示无时限
USE_TIME_MODE = True  # True: 限时模式；False: 完成模式

# 练习状态
current_text = ""
typed = ""
cursor_pos = 0
start_time = None
elapsed = 0.0
active = False
finished = False
errors = 0
total_keystrokes = 0
wpm = 0.0
accuracy = 100.0

# 换段或初始化


def new_round():
    global current_text, typed, cursor_pos, start_time, elapsed, errors, total_keystrokes, active, finished, wpm, accuracy
    current_text = random.choice(PARAGRAPHS)
    typed = ""
    cursor_pos = 0
    start_time = None
    elapsed = 0.0
    errors = 0
    total_keystrokes = 0
    active = False
    finished = False
    wpm = 0.0
    accuracy = 100.0


new_round()

# 计算统计


def compute_stats():
    global wpm, accuracy, elapsed
    if not start_time:
        elapsed = 0.0
    else:
        elapsed = time.time() - start_time
    minutes = max(1/60.0, elapsed/60.0)
    # 以正确字符数计算 WPM（每5字符为一个单词）
    correct_chars = sum(1 for i, ch in enumerate(
        typed) if i < len(current_text) and ch == current_text[i])
    wpm = (correct_chars / 5.0) / minutes
    accuracy = (correct_chars / max(1, len(typed))) * 100 if typed else 100.0
    return wpm, accuracy

# 渲染带换行的字符高亮文本（按字符逐个绘制并在超宽时换行）


def render_text_block(text, typed_text, x, y, max_w):
    tx = x
    ty = y
    line_height = FONT.get_height() + 6
    for i, ch in enumerate(list(text)):
        surf = FONT.render(ch, True, TEXT_COLOR)
        w = surf.get_width()
        if tx + w > x + max_w:
            tx = x
            ty += line_height
        color = TEXT_COLOR
        if i < len(typed_text):
            color = GOOD if typed_text[i] == ch else BAD
        screen.blit(FONT.render(ch, True, color), (tx, ty))
        tx += w
    return tx, ty, line_height

# 绘制界面


def draw_ui():
    screen.fill(BG)
    # 顶部面板
    pygame.draw.rect(screen, PANEL, (20, 20, WIDTH-40, 60), border_radius=6)
    screen.blit(FONT_BIG.render("打字练习", True, ACCENT), (36, 28))
    mode_text = f"限时模式: {TIME_LIMIT}s" if USE_TIME_MODE else "完成模式"
    screen.blit(SMALL.render(mode_text, True, HINT), (36, 68))

    # 中央文本面板
    pygame.draw.rect(screen, (18, 22, 26),
                     (20, 100, WIDTH-40, 320), border_radius=6)
    max_w = WIDTH-40-24
    start_x = 32
    start_y = 116
    tx, ty, line_h = render_text_block(
        current_text, typed, start_x, start_y, max_w)

    # 计算光标位置（根据 cursor_pos 在文本中的坐标）
    tx = start_x
    ty = start_y
    pos = 0
    for i, ch in enumerate(list(current_text)):
        surf = FONT.render(ch, True, TEXT_COLOR)
        w = surf.get_width()
        if tx + w > start_x + max_w:
            tx = start_x
            ty += line_h
        if pos == cursor_pos:
            break
        tx += w
        pos += 1
    # 如果 cursor 在文本末尾且超出最后一行，tx/ty 已经是合适位置
    if active and not finished:
        pygame.draw.rect(screen, CURSOR_COLOR, (tx, ty, 2, FONT.get_height()))

    # 底部统计框
    pygame.draw.rect(screen, PANEL, (20, 440, WIDTH-40, 120), border_radius=6)
    compute_stats()
    stats = [
        f"时间: {int(elapsed)}s",
        f"WPM: {int(wpm)}",
        f"准确率: {accuracy:.1f}%",
        f"错误: {errors}",
        f"输入长度: {len(typed)}/{len(current_text)}"
    ]
    for i, s in enumerate(stats):
        screen.blit(SMALL.render(s, True, TEXT_COLOR), (36 + i*200, 452))

    screen.blit(SMALL.render(
        "空格/Enter 开始  |  R 重置  |  N 新段落  |  Esc 退出", True, HINT), (36, 492))

    # 完成或时间到的覆盖
    if finished or (USE_TIME_MODE and start_time and elapsed >= TIME_LIMIT):
        overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
        overlay.fill((0, 0, 0, 180))
        screen.blit(overlay, (0, 0))
        box_w, box_h = 600, 300
        bx = (WIDTH-box_w)//2
        by = (HEIGHT-box_h)//2
        pygame.draw.rect(screen, (26, 28, 32),
                         (bx, by, box_w, box_h), border_radius=8)
        pygame.draw.rect(screen, ACCENT, (bx+12, by+12,
                         box_w-24, 40), border_radius=6)
        screen.blit(FONT_BIG.render(
            "练习结束", True, (10, 10, 10)), (bx+24, by+18))
        screen.blit(FONT.render(
            f"用时: {int(elapsed)} s", True, TEXT_COLOR), (bx+24, by+80))
        screen.blit(FONT.render(
            f"WPM: {int(wpm)}", True, TEXT_COLOR), (bx+24, by+110))
        screen.blit(FONT.render(
            f"准确率: {accuracy:.1f}%", True, TEXT_COLOR), (bx+24, by+140))
        screen.blit(FONT.render(
            f"错误数: {errors}", True, TEXT_COLOR), (bx+24, by+170))
        screen.blit(SMALL.render("按 N 开始新段落，R 重新开始当前段，Esc 退出",
                    True, HINT), (bx+24, by+210))

    pygame.display.flip()


# 主循环
running = True
while running:
    dt = clock.tick(60) / 1000.0
    for ev in pygame.event.get():
        if ev.type == pygame.QUIT:
            running = False
        elif ev.type == pygame.KEYDOWN:
            if ev.key == pygame.K_ESCAPE:
                running = False
            elif ev.key == pygame.K_r:
                new_round()
            elif ev.key == pygame.K_n:
                new_round()
            elif ev.key in (pygame.K_SPACE, pygame.K_RETURN):
                # 如果还没开始，按空格或回车开始；如果已开始且是完成模式，回车提交并结束
                if not active and not finished:
                    active = True
                    start_time = time.time()
                elif active and not finished and not USE_TIME_MODE and ev.key == pygame.K_RETURN:
                    # 在完成模式按回车也可以结束（如果希望强制提交）
                    if len(typed) >= len(current_text):
                        finished = True
            elif ev.key == pygame.K_BACKSPACE:
                if active and not finished and len(typed) > 0:
                    typed = typed[:-1]
                    cursor_pos = max(0, cursor_pos-1)
                    total_keystrokes += 1
                    # 重新计算 errors
                    errors = sum(1 for i, ch in enumerate(typed) if i < len(
                        current_text) and ch != current_text[i])
            else:
                # 处理普通字符（包括中文）
                if active and not finished:
                    ch = ev.unicode
                    if ch:
                        typed += ch
                        cursor_pos += 1
                        total_keystrokes += 1
                        # 检查是否错误
                        if cursor_pos-1 < len(current_text):
                            if ch != current_text[cursor_pos-1]:
                                errors += 1
                        else:
                            errors += 1
                        # 若为完成模式并且输入长度达到或超过文本长度，标为完成
                        if not USE_TIME_MODE and len(typed) >= len(current_text):
                            finished = True

    # 更新计时与结束条件
    if active and start_time:
        elapsed = time.time() - start_time
        if USE_TIME_MODE and TIME_LIMIT > 0 and elapsed >= TIME_LIMIT:
            elapsed = TIME_LIMIT
            finished = True

    # 计算统计（更新全局变量）
    wpm, accuracy = compute_stats()

    draw_ui()

pygame.quit()
sys.exit()
