"""Safe single-key YAML frontmatter reader (ORCH-016 / ADR-001 §5).

The status-comment builder (build_status_comment) needs to surface verdict /
deploy_status / staging_status from the per-stage artifact files (12-review.md,
13-test-report.md, 14-deploy-log.md, 15-staging-log.md). Those files share the
same leading-YAML-frontmatter convention used by the quality gates — but the
comment hot-path must NEVER raise: a missing file, malformed YAML, or absent
key should simply suppress the verdict line, not break the run.

This module is a tiny defensive helper:
  - `read_frontmatter_value(path, key)` -> str | None
  - swallows every exception, logs to logger.debug, returns None.

It intentionally duplicates ~10 lines of YAML-frontmatter logic that already
exist in `src/qg/checks.py` (S-5 / БАГ 8 / ET-013 fixes). ADR-001 §5 accepts
this duplication to keep the blast radius of ORCH-016 small (no QG refactor in
this PR); merging into a single parser is a follow-up task.
"""

import logging

logger = logging.getLogger("orchestrator.frontmatter")


def read_frontmatter_value(path: str, key: str) -> str | None:
    """Return the value of `key` from the leading YAML frontmatter of `path`.

    Format expected (canonical, matching qg/checks.py):
        ---
        key: value
        other: ...
        ---
        <body>

    Never raises. Returns None for any of:
      - missing/unreadable file,
      - no leading `---` frontmatter,
      - malformed/unterminated frontmatter,
      - YAML parse error,
      - frontmatter is not a mapping,
      - key absent (or its value is None/empty).

    The returned value is stringified and stripped (whitespace removed); casing
    is preserved so the caller decides whether to upper/lower for matching.
    """
    try:
        with open(path, "r", encoding="utf-8", errors="replace") as f:
            content = f.read()
    except OSError as e:
        logger.debug(f"read_frontmatter_value: cannot open {path}: {e}")
        return None

    if not content.startswith("---"):
        return None

    parts = content.split("---", 2)
    if len(parts) < 3:
        # Unterminated frontmatter.
        return None

    try:
        import yaml
        fm = yaml.safe_load(parts[1]) or {}
    except Exception as e:  # yaml.YAMLError + anything pyyaml may surface
        logger.debug(f"read_frontmatter_value: yaml parse failed for {path}: {e}")
        return None

    if not isinstance(fm, dict):
        return None

    raw = fm.get(key)
    if raw is None:
        return None
    value = str(raw).strip()
    return value or None
