"""Surgical, value-free edits to a declared ``SECRETS.toml`` entry (SPEC-P5 §1).

The registry is the single source of truth, so a verb that must record state onto
it (``retire`` flips ``state``; ``rotate`` stamps ``rotation.last``) edits **only the
one field**, leaving every neighbouring line byte-identical so the change is a
minimal, reviewable git diff. No secret value is ever touched here — these editors
operate purely on declared metadata (AG-18).

``retire.py`` keeps its own ``flip_state_in_file`` (the P3 shape); this module is the
P5 addition for the rotation stamp and shares the entry-span scan.
"""

from __future__ import annotations

import re
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from pathlib import Path

#: A TOML table header line: ``[name]`` / ``[name.sub]`` / ``[[name.array]]``.
_HEADER_RE = re.compile(r"^\s*\[\[?\s*([^\]\[]+?)\s*\]\]?\s*(?:#.*)?$")
#: An inline ``rotation = { … }`` assignment (the live registry shape).
_ROTATION_INLINE_RE = re.compile(r"^(\s*rotation\s*=\s*\{)(.*)(\}\s*)$")
#: A ``last = "…"`` key inside an inline table body or a rotation sub-table line.
_LAST_RE = re.compile(r"""(\blast\s*=\s*)(["']).*?(["'])""")


def entry_span(lines: list[str], entry_id: str) -> tuple[int, int] | None:
    """``[start, end)`` line range of ``[entry_id]`` incl. its sub-tables / arrays.

    Mirrors ``retire._entry_span`` so both verbs scope their edits identically.
    """
    start: int | None = None
    for i, ln in enumerate(lines):
        m = _HEADER_RE.match(ln)
        if m and m.group(1).strip() == entry_id and not ln.lstrip().startswith("[["):
            start = i
            break
    if start is None:
        return None
    end = len(lines)
    for j in range(start + 1, len(lines)):
        m = _HEADER_RE.match(lines[j])
        if m and m.group(1).split(".")[0].strip() != entry_id:
            end = j
            break
    return start, end


def _stamp_inline(body: str, date: str) -> str:
    """Set/insert ``last = "date"`` inside an inline-table ``body`` (between the braces)."""
    if _LAST_RE.search(body):
        return _LAST_RE.sub(rf"\g<1>\g<2>{date}\g<3>", body, count=1)
    trimmed = body.rstrip()
    sep = "" if not trimmed or trimmed.endswith(",") else ","
    tail = body[len(trimmed) :] or " "
    return f'{trimmed}{sep} last = "{date}"{tail}'


def set_rotation_last_in_file(path: Path, entry_id: str, date: str) -> bool:
    """Set ``entry_id``'s ``rotation.last`` to ``date`` in ``path`` (surgical).

    Handles both the inline ``rotation = { … }`` form (updating/inserting ``last``
    between the braces) and a multi-line ``[entry_id.rotation]`` sub-table (updating an
    existing ``last`` line). Returns True iff the stamp was written. Only that field's
    line changes; ``date`` is a plain ``YYYY-MM-DD`` string (never a secret).
    """
    text = path.read_text(encoding="utf-8")
    lines = text.splitlines(keepends=True)
    span = entry_span(lines, entry_id)
    if span is None:
        return False
    start, end = span
    for k in range(start, end):
        raw = lines[k]
        eol = "\n" if raw.endswith("\n") else ""
        stripped = raw.rstrip("\n")
        m = _ROTATION_INLINE_RE.match(stripped)
        if m:
            lines[k] = f"{m.group(1)}{_stamp_inline(m.group(2), date)}{m.group(3)}{eol}"
            path.write_text("".join(lines), encoding="utf-8")
            return True
    # Multi-line sub-table fallback: a bare ``last = "…"`` line inside the entry span.
    for k in range(start, end):
        stripped = lines[k].rstrip("\n")
        if _LAST_RE.search(stripped) and "rotation" not in stripped:
            eol = "\n" if lines[k].endswith("\n") else ""
            lines[k] = _LAST_RE.sub(rf"\g<1>\g<2>{date}\g<3>", stripped, count=1) + eol
            path.write_text("".join(lines), encoding="utf-8")
            return True
    return False
