"""Post-mortem writer for VM scenario runs.

write_post_mortem() creates a markdown file at:
  {root}/post-mortems/{vm_name}/{scenario_name}/{timestamp}.md

The write is atomic (tempfile + rename).
"""

from __future__ import annotations

import os
import tempfile
from datetime import UTC, datetime
from pathlib import Path

from mcp_vm_blackbox._helpers import default_blackbox_data_root
from mcp_vm_blackbox.models import PostMortem, VerificationReport


def write_post_mortem(
    vm_name: str,
    scenario_name: str,
    steps: list[dict[str, str | None]],
    verification_report: VerificationReport | None,
    root: Path | None = None,
) -> PostMortem:
    """Write post-mortem markdown to {root}/post-mortems/{vm}/{scenario}/{ts}.md.

    Returns a PostMortem model with post_mortem_path set to the written file's
    absolute path as a string. The write is atomic (temp file + rename).

    Args:
        vm_name: Virtual machine name segment in the output path.
        scenario_name: Scenario name segment in the output path.
        steps: Step rows (name, outcome, optional DER fields) to render.
        verification_report: Optional verification summary to embed in the markdown.
        root: Storage root; defaults to :func:`~mcp_vm_blackbox._helpers.default_blackbox_data_root`.
    """
    effective_root = root if root is not None else default_blackbox_data_root()
    timestamp = datetime.now(UTC).strftime("%Y%m%dT%H%M%SZ")
    out_dir = effective_root / "post-mortems" / vm_name / scenario_name
    out_dir.mkdir(parents=True, exist_ok=True)
    out_path = out_dir / f"{timestamp}.md"

    content = _render_markdown(vm_name, scenario_name, timestamp, steps, verification_report)

    fd, tmp = tempfile.mkstemp(dir=out_dir, suffix=".tmp")
    try:
        with os.fdopen(fd, "w", encoding="utf-8") as f:
            f.write(content)
        Path(tmp).rename(out_path)
    except Exception:
        Path(tmp).unlink(missing_ok=True)
        raise

    return PostMortem(
        vm_name=vm_name,
        scenario_name=scenario_name,
        timestamp=timestamp,
        steps=steps,
        verification_report=verification_report,
        post_mortem_path=str(out_path.resolve()),
    )


_DER_FIELDS: frozenset[str] = frozenset({
    "intent",
    "reason",
    "outcome_status",
    "outcome_detail",
    "issue_classification",
    "resolution",
    "next",
})


def _has_der_fields(step: dict[str, str | None]) -> bool:
    """Return True if any DER field in the step dict is non-None."""
    return any(step.get(field) is not None for field in _DER_FIELDS)


def _render_step_der(index: int, step: dict[str, str | None]) -> list[str]:
    """Render a step that has at least one DER field as a structured block."""
    action = step.get("action") or step.get("name") or "(unnamed)"
    outcome_status = step.get("outcome_status") or step.get("outcome") or "N/A"
    outcome_detail = step.get("outcome_detail") or ""
    outcome_line = f"{outcome_status}" + (f" -- {outcome_detail}" if outcome_detail else "")

    issue_classification = step.get("issue_classification") or "none"
    resolution = step.get("resolution") or ""
    issue_line = f"{issue_classification}" + (f" -- {resolution}" if resolution else "")

    return [
        f"### Step {index}: {action}",
        f"- **Intent:** {step.get('intent') or 'N/A'}",
        f"- **Reason:** {step.get('reason') or 'N/A'}",
        f"- **Outcome:** {outcome_line}",
        f"- **Issue:** {issue_line}",
        f"- **Next:** {step.get('next') or 'N/A'}",
        "",
    ]


def _render_markdown(
    vm_name: str,
    scenario_name: str,
    timestamp: str,
    steps: list[dict[str, str | None]],
    verification_report: VerificationReport | None,
) -> str:
    lines: list[str] = [
        f"# Post-Mortem: {vm_name}/{scenario_name}",
        f"**Timestamp:** {timestamp}",
        f"**Composite Key:** {vm_name}/{scenario_name}",
        "",
        "## Steps",
        "",
    ]

    for i, step in enumerate(steps, start=1):
        if _has_der_fields(step):
            lines.extend(_render_step_der(i, step))
        else:
            action = step.get("action") or step.get("name") or "(unnamed)"
            outcome = step.get("outcome") or "(no outcome)"
            lines.append(f"- {action}: {outcome}")

    lines.extend(("", "## Verification Results", ""))

    if verification_report is None:
        lines.append("No verification run recorded.")
    else:
        overall = "PASS" if verification_report.passed else "FAIL"
        lines.append(f"**Overall:** {overall}")
        for result in verification_report.results:
            status = "PASS" if result.passed else "FAIL"
            lines.append(
                f"- [{status}] {result.criterion_type} on {result.host}: "
                f"expected={result.expected}, actual={result.actual}"
            )

    return "\n".join(lines) + "\n"
