"""Step renderers and walkthrough discovery for the closeout ceremony.

Each renderer returns a text block for exactly one ceremony step.
Split from ``closeout_ceremony.py`` to keep both modules under 600 lines.
"""

from __future__ import annotations

from pathlib import Path
from typing import TYPE_CHECKING, Any

from rich.console import Group
from rich.markdown import Markdown
from rich.rule import Rule
from rich.text import Text

from gzkit.commands.ceremony_data import (
    _render_to_text,
    check_doc_alignment,
    extract_adr_intent,
    extract_brief_metadata,
    format_doc_table,
    format_summary_table,
)
from gzkit.commands.ceremony_intent import (
    format_intent_pairing_table,
    pair_intent_with_obpis,
    parse_intent_items,
)

if TYPE_CHECKING:
    from gzkit.commands.closeout_ceremony import CeremonyState


# ---------------------------------------------------------------------------
# Step renderers — each returns a text block for exactly one step
# ---------------------------------------------------------------------------


def render_step_1_readiness(
    adr_id: str,
    obpi_rows: list[dict[str, Any]],
    readiness: dict[str, Any],
) -> str:
    """OBPI completion table — the precondition proof."""
    from gzkit.commands.ceremony_data import format_readiness_table

    return format_readiness_table(adr_id, obpi_rows, readiness)


def render_step_2_summary(
    adr_id: str,
    adr_file: Path,
    obpi_files: list[Path],
    lane: str,
    project_root: Path,
) -> str:
    """Scope Review — ADR intent paired with OBPI Bill of Materials (GHI-155).

    Step 2's operator role is semantic scope review: the human's first chance
    in the ceremony to ask *does the work these OBPIs delivered match what
    the parent ADR promised?* Step 1 already proved readiness; Step 2 adds
    the scope-vs-promise check. To enable it, this renderer pulls the parent
    ADR's ``## Intent`` section and presents it alongside the BOM table so
    the operator can answer the question without opening the ADR in another
    window.
    """
    briefs = [extract_brief_metadata(f) for f in obpi_files]
    intent = extract_adr_intent(adr_file)
    intent_items = parse_intent_items(intent) if intent else []

    lines = [
        "I am now in PASSIVE PRESENTER mode. I will not interpret evidence.",
        "",
        "Step 2 — Scope Review: does the delivered work match the ADR's intent?",
        "",
        f"ADR: {adr_file.relative_to(project_root).as_posix()}",
        f"Lane: {lane}",
        "",
    ]

    if intent_items:
        pairings = pair_intent_with_obpis(intent_items, briefs)
        lines.append(format_intent_pairing_table(pairings))
    elif intent:
        lines.append("ADR Intent (from parent ADR):")
        for intent_line in intent.splitlines():
            lines.append(f"  {intent_line}" if intent_line else "")
    else:
        lines.append("ADR Intent (from parent ADR):")
        lines.append("  (parent ADR has no `## Intent` section — review the ADR doc directly)")

    lines.extend(
        [
            "",
            format_summary_table(
                briefs,
                title=f"Bill of Materials — {adr_id}",
            ),
            "",
            f"Scope review question: do the {len(briefs)} OBPI objectives above",
            "collectively match the ADR Intent? Any objective missing from scope?",
            "Any objective delivered that the ADR did not promise? Acknowledge to",
            "proceed, or request corrections before advancing.",
            "",
            f"Step 2 complete. Run `gz closeout {adr_id} --ceremony --next`",
            "to proceed to docs alignment check.",
        ]
    )
    return "\n".join(lines)


def render_step_3_docs_check(
    adr_id: str,
    project_root: Path,
    obpi_files: list[Path],
) -> str:
    """Docs alignment findings — agent homework, human reviews."""
    results = check_doc_alignment(project_root, obpi_files)

    lines = [format_doc_table(results)]

    if results:
        missing = [r for r in results if not r["manpage_exists"]]
        if missing:
            lines.append("")
            lines.append(f"GAPS: {len(missing)} command(s) missing manpages.")
        else:
            lines.append("")
            lines.append("All command manpages present.")
    else:
        lines.append("")
        lines.append("Manual review: check that any new/changed commands have documentation.")

    lines.append("")
    lines.append(f"Step 3 complete. Run `gz closeout {adr_id} --ceremony --next`")
    lines.append("to proceed to value walkthrough.")
    return "\n".join(lines)


def render_step_4_walkthrough(
    adr_id: str,
    commands: list[str],
    obpi_files: list[Path],
) -> str:
    """Value narrative — per-OBPI sections, then demo command list."""
    briefs = [extract_brief_metadata(f) for f in obpi_files]
    elements: list[Any] = [Rule("Value Walkthrough")]

    for b in briefs:
        obpi_id = b.get("id", "?")
        title = b.get("title", "?")
        objective = b.get("objective", "(no objective recorded)")
        first_para = objective.split("\n\n")[0].strip()

        md_lines = [f"### {obpi_id}: {title}", "", first_para]
        elements.append(Markdown("\n".join(md_lines)))

        ac = b.get("acceptance_criteria", [])
        if ac:
            elements.append(Text())
            elements.append(Rule(f"Requirements ({len(ac)})", style="dim", align="left"))
            ac_md = "\n".join(f"- {c}" for c in ac)
            elements.append(Markdown(ac_md))

        elements.append(Text())
        elements.append(Text())

    if commands:
        elements.append(Rule("Demo Commands (Step 5)", style="dim"))
        for i, c in enumerate(commands):
            elements.append(Text(f"  {i + 1}. {c}"))
    else:
        elements.append(Text("No demo commands discovered."))

    elements.append(Text())
    elements.append(
        Text(
            f"Step 4 complete. Run `gz closeout {adr_id} --ceremony --next`\n"
            "to begin the live demo."
        )
    )
    return _render_to_text(Group(*elements))


def render_step_5_execute(
    adr_id: str,
    commands: list[str],
    walkthrough_index: int = 0,
) -> str:
    """Live demo — present ONE command per render for operator-paced execution.

    GHI #260: the CLI gates each demo command behind its own ``--next``. The
    walkthrough is the operator's observation surface; batching demos into a
    single render eliminates the per-command ack loop the ceremony depends on.

    ``walkthrough_index`` selects which command this render shows. At index
    ``len(commands) - 1`` the agent runs the final demo and the next ``--next``
    advances the ceremony to Step 6 ATTESTATION.
    """
    if not commands:
        return "\n".join(
            [
                "LIVE DEMO — Test Drive",
                "",
                "No demo commands to run.",
                "",
                f"Run `gz closeout {adr_id} --ceremony --next` to proceed to attestation.",
            ]
        )

    total = len(commands)
    index = max(0, min(walkthrough_index, total - 1))
    current = commands[index]
    position = f"{index + 1} of {total}"
    remaining = total - index - 1
    if remaining == 0:
        advance_hint = (
            f"After the human acknowledges this final command, run `gz closeout "
            f"{adr_id} --ceremony --next` to proceed to attestation."
        )
    else:
        advance_hint = (
            f"After the human acknowledges this command, run `gz closeout "
            f"{adr_id} --ceremony --next` to present the next demo "
            f"({remaining} remaining)."
        )

    return "\n".join(
        [
            f"LIVE DEMO — Test Drive ({position})",
            "",
            "For this command:",
            "  1. Explain briefly why it demonstrates value",
            "  2. Run it (or offer to let the human run it)",
            "  3. Wait for human acknowledgment before advancing",
            "",
            "Command to demonstrate now:",
            f"  `{current}`",
            "",
            advance_hint,
        ]
    )


def render_step_6_attestation(adr_id: str) -> str:
    """Request attestation — supports R&R dialogue.

    Prompt ordering honors the gz-adr-closeout-ceremony skill Step 5
    contract (GHI #250): the agent will now present the structured
    Evidence Summary, and only then does the operator decide. The
    previous prompt listed operator moves first and closed with "I
    await your decision", which read as an operator-driven pattern
    and contradicted the skill's proactive-evidence directive.

    Closeout proof is rendered by the derived ``gz validate --closeout-proof``
    view (ADR-0.0.69), not by a per-brief ``ln:`` binding table — the ``ln:``
    consumer was retired with its producer (GHI #601).
    """
    lines = [
        "ATTESTATION — Your Verdict",
        "",
    ]

    lines.extend(
        [
            "The walkthrough is complete. Per the gz-adr-closeout-ceremony",
            "skill Step 5 contract, the agent will now present the structured",
            "Evidence Summary (see the skill template). Once you have the",
            "summary, you may:",
            "",
            "  Ask questions — the agent answers factually without interpreting",
            "  Request re-runs — ask to see any command output again",
            "  Direct revisions — identify issues to fix before attesting",
            "",
            "When you are satisfied, provide your attestation:",
            "",
            f'  gz closeout {adr_id} --ceremony --attest "Completed"',
            f'  gz closeout {adr_id} --ceremony --attest "Completed - Partial: [reason]"',
            f'  gz closeout {adr_id} --ceremony --attest "Dropped - [reason]"',
            "",
            "To pause for revisions (revise and resubmit):",
            "",
            f"  gz closeout {adr_id} --ceremony --pause",
            "",
            "Agent: present the Evidence Summary Template now, then await",
            "the operator's decision.",
        ]
    )
    return "\n".join(lines)


def render_step_7_closeout(adr_id: str) -> str:
    """Instruct the agent to run the closeout pipeline."""
    return "\n".join(
        [
            "CLOSEOUT PIPELINE — Agent Executes, Human Observes",
            "",
            "Run the closeout pipeline (quality gates, attestation record,",
            "version bump, closeout form):",
            "",
            f"  uv run gz closeout {adr_id}",
            "",
            "Present each sub-action and its result as it runs.",
            "",
            f"After closeout completes, run `gz closeout {adr_id} --ceremony --next`.",
        ]
    )


def render_step_8_issues(adr_id: str) -> str:
    """Instruct the agent to investigate and close related GitHub issues."""
    return "\n".join(
        [
            "GITHUB ISSUES — Investigate and Close",
            "",
            "Find related issues:",
            "",
            f'  gh issue list --search "{adr_id}" --state open',
            "",
            "For each issue, present: number, title, proposed disposition, reasoning.",
            "Wait for human confirmation before closing.",
            "",
            f'  gh issue close <number> --comment "Resolved by {adr_id} closeout."',
            "",
            "If any issue reveals incomplete work, flag it as a blocker.",
            "",
            f"After reviewing issues, run `gz closeout {adr_id} --ceremony --next`.",
        ]
    )


def render_step_9_release_notes(adr_id: str, is_foundation: bool) -> str:
    """Release notes — foundation-aware."""
    if is_foundation:
        return "\n".join(
            [
                "RELEASE NOTES — Foundation Patch",
                "",
                f"{adr_id} is a foundation ADR (0.0.x).",
                "Foundation patches contribute to the next batch release.",
                "",
                "Note: ADR-0.0.15 (ghi-driven-patch-release-ceremony) will",
                "formalize the foundation patch release flow.",
                "",
                "Ensure this ADR's contributions are noted for the next release.",
                "",
                f"Run `gz closeout {adr_id} --ceremony --next` to proceed.",
            ]
        )
    return "\n".join(
        [
            "RELEASE NOTES — Update RELEASE_NOTES.md",
            "",
            "Add a new release entry for this ADR:",
            "",
            "  ## vX.Y.Z (YYYY-MM-DD)",
            f"  **ADR:** {adr_id}",
            "  [Brief description of delivered value]",
            "  ### Delivered",
            "  - [Key deliverables from each OBPI]",
            "  ### Gate Evidence",
            "  All 5 GovZero gates satisfied.",
            "",
            f"After updating, run `gz closeout {adr_id} --ceremony --next`.",
        ]
    )


def render_step_10_release(adr_id: str, is_foundation: bool) -> str:
    """GitHub release — the certificate."""
    if is_foundation:
        return "\n".join(
            [
                "RELEASE — Foundation (Deferred)",
                "",
                "Foundation ADRs do not create standalone GitHub releases.",
                "The release will be included in the next patch version.",
                "",
                f"Run `gz closeout {adr_id} --ceremony --next` to complete.",
            ]
        )
    return "\n".join(
        [
            "RELEASE — Create GitHub Release",
            "",
            "  # MANDATORY: sync before release",
            "  uv run gz git-sync --apply --lint --test",
            "",
            "  # Verify all version references are in sync",
            "  # (pyproject.toml, README badge, RELEASE_NOTES.md)",
            "",
            '  gh release create vX.Y.Z --title "vX.Y.Z" --notes "..."',
            "",
            f"After creating the release, run `gz closeout {adr_id} --ceremony --next`.",
        ]
    )


def render_step_11_complete(state: CeremonyState) -> str:
    """Ceremony completion — value-landed statement."""
    step_names = {
        1: "Readiness verified",
        2: "Bill of materials presented",
        3: "Docs alignment checked",
        4: "Value walkthrough presented",
        5: "Live demo executed",
        6: "Attestation recorded",
        7: "Closeout pipeline executed",
        8: "GitHub issues reviewed",
        9: "Release notes updated",
        10: "GitHub release created",
        11: "Ceremony complete",
    }
    lines = [
        f"ADR {state.adr_id} CLOSEOUT CEREMONY — COMPLETE",
        "",
        "Steps completed:",
    ]
    for record in state.step_history:
        name = step_names.get(record.step, f"Step {record.step}")
        marker = "  " if record.acknowledged_at else ">>"
        lines.append(f"  {marker} Step {record.step:2d}: {name}")

    if state.attestation:
        lines.append(f"\n  Attestation: {state.attestation}")

    lines.append("")
    lines.append("Value landed. Run `gz git-sync --apply --lint --test` to sync.")
    return "\n".join(lines)
