"""Parse regimen markdown files into steps."""

from __future__ import annotations

import re
from dataclasses import dataclass, field


@dataclass
class Command:
    """A bash command with an optional timeout override."""

    code: str
    timeout: int | None = None


@dataclass
class Step:
    """A single verification step: prose description + commands to run."""

    title: str
    prose: str
    commands: list[Command] = field(default_factory=list)


@dataclass
class Regimen:
    """A parsed regimen file."""

    title: str
    steps: list[Step] = field(default_factory=list)


def _flush_prose(step: Step, prose_lines: list[str]) -> None:
    """Append accumulated prose lines to step, skipping if empty."""
    chunk = "\n".join(prose_lines).strip()
    if not chunk:
        return
    if step.prose:
        step.prose += "\n" + chunk
    else:
        step.prose = chunk


def parse(text: str) -> Regimen:
    """Parse markdown text into a Regimen.

    Top-level `#` heading becomes the regimen title. Each `##` heading
    starts a new step. Prose is everything between the heading and the
    code blocks. Fenced ```bash blocks become commands.
    """
    lines = text.split("\n")
    regimen_title = ""
    steps: list[Step] = []

    current_step: Step | None = None
    in_code_block = False
    code_lines: list[str] = []
    code_timeout: int | None = None
    prose_lines: list[str] = []

    for line in lines:
        # Detect fenced code block boundaries
        fence_match = re.match(r"^```bash(?:\s+timeout=(\d+))?\s*$", line)
        if fence_match:
            in_code_block = True
            code_lines = []
            code_timeout = int(fence_match.group(1)) if fence_match.group(1) else None
            continue
        if in_code_block and re.match(r"^```\s*$", line):
            in_code_block = False
            if current_step is not None:
                _flush_prose(current_step, prose_lines)
                prose_lines = []
                current_step.commands.append(Command("\n".join(code_lines), code_timeout))
            code_lines = []
            code_timeout = None
            continue
        if in_code_block:
            code_lines.append(line)
            continue

        # Top-level heading
        match_h1 = re.match(r"^#\s+(.+)$", line)
        if match_h1 and not regimen_title:
            regimen_title = match_h1.group(1).strip()
            continue

        # Step heading
        match_h2 = re.match(r"^##\s+(.+)$", line)
        if match_h2:
            if current_step is not None:
                _flush_prose(current_step, prose_lines)
                prose_lines = []
                steps.append(current_step)
            current_step = Step(title=match_h2.group(1).strip(), prose="")
            prose_lines = []
            continue

        # Accumulate prose
        if current_step is not None:
            prose_lines.append(line)

    # Flush last step
    if current_step is not None:
        _flush_prose(current_step, prose_lines)
        steps.append(current_step)

    return Regimen(title=regimen_title, steps=steps)
