﻿from __future__ import annotations

import re
from dataclasses import dataclass

from rich.text import Text


@dataclass(frozen=True)
class LyricLine:
    seconds: float | None
    text: str


_TIMESTAMP = re.compile(r"\[(\d{1,2}):(\d{2})(?:\.(\d{1,3}))?\]")


def parse_lyrics(lyrics: str | None) -> list[LyricLine]:
    if not lyrics:
        return []
    parsed: list[LyricLine] = []
    for raw in lyrics.splitlines():
        line = raw.strip()
        if not line:
            continue
        match = _TIMESTAMP.search(line)
        if match:
            minutes = int(match.group(1))
            seconds = int(match.group(2))
            fraction = match.group(3) or "0"
            total = minutes * 60 + seconds + int(fraction.ljust(3, "0")[:3]) / 1000
            text = _TIMESTAMP.sub("", line).strip()
            parsed.append(LyricLine(total, text or line))
        else:
            parsed.append(LyricLine(None, line))
    return parsed


def lyric_index_at(lines: list[LyricLine], current_seconds: float) -> int:
    if not lines:
        return 0
    current = 0
    for index, line in enumerate(lines):
        if line.seconds is not None and line.seconds <= current_seconds:
            current = index
        elif line.seconds is not None and line.seconds > current_seconds:
            break
    return current


def format_lyrics(lyrics: str | None = None, *, current_seconds: float = 0, radius: int = 7, lines: list[LyricLine] | None = None) -> Text:
    parsed = lines if lines is not None else parse_lyrics(lyrics)
    if not parsed:
        return Text("暂无歌词", justify="center", style="dim")
    current = lyric_index_at(parsed, current_seconds)
    start = max(0, current - radius)
    end = min(len(parsed), current + radius + 1)
    output = Text(justify="center")
    for index in range(start, end):
        if index > start:
            output.append("\n")
        style = "bold bright_cyan" if index == current else "dim"
        output.append(f"  {parsed[index].text}", style=style)
    return output
