"""리포트에서 clarification 행을 읽는다 — 어느 스키마가 썼든.

schema-v2 는 `.data.json` 의 `clarificationItems[]`, schema-v1 은 §1 표다.
읽기 함수가 텍스트가 아니라 **경로**를 받는 이유가 이것이다.
"""
from __future__ import annotations

from ..final_report_paths import final_report_data_path
from ..json_boundary import load_owned_object
from pathlib import Path
from typing import Optional
from .parsing import (
    ClarificationItem,
    parse_section_1_rows,
)
from .dispositions import (
    clarification_disposition,
)


STRUCTURED_REPORT_VERSIONS = frozenset({"2.0", "3.0"})


def _read_report_text(report_path: Path) -> str:
    return report_path.read_text(encoding="utf-8", errors="replace")


def _structured_report_data(report_path: Path) -> Optional[dict]:
    """``report_path`` 의 구조화 리포트 레코드, 아니면 ``None``.

    파일이 없거나 JSON 이 깨졌거나 구조화 판본이 아니면 ``None`` — 호출자는 v1
    마크다운 경로로 폴백하고, 진짜 구조화 리포트인데 레코드가 깨진 경우는 그
    폴백이 "§1 없음" fail-closed 로 잡는다.

    판본을 `2.0` 하나로 못박아 두던 동안 3.0 리포트가 여기서 ``None`` 이 됐고,
    그러면 호출자가 JSON 본문에서 `## 1.` 헤딩을 찾다 실패해 **리포트 전문을
    그대로 복사**했다 — 이 좁히기가 막으려던 바로 그 중복이다. 실측: 66K 짜리
    추출본이 나와야 할 자리에 693K data.json 이 스테이징됐고, 패킷의
    `## Clarification Carry-In Extract` 가 0행이 되어 워커가 사용자 답변을
    전혀 받지 못했다.
    """
    data_path = final_report_data_path(report_path)
    if not data_path.is_file():
        return None
    try:
        data = load_owned_object(data_path, artifact="final report record")
    except (OSError, ValueError):
        return None
    if (
        not isinstance(data, dict)
        or data.get("schemaVersion") not in STRUCTURED_REPORT_VERSIONS
    ):
        return None
    return data


def _v2_row(entry: dict) -> Optional[dict]:
    """``clarificationItems[]`` 한 행을 §1 행과 같은 shape 으로. 필수 필드가
    빠졌으면 ``None`` — 호출자가 fail-closed 로 셀 수 있게 한다."""
    row_id = entry.get("id")
    raw_blocks = entry.get("blocks")
    raw_status = entry.get("status")
    if not (isinstance(row_id, str) and row_id):
        return None
    if not (isinstance(raw_blocks, str) and raw_blocks):
        return None
    if not (isinstance(raw_status, str) and raw_status):
        return None
    kind = entry.get("kind")
    item = ClarificationItem(
        row_id=row_id,
        kind=kind.lower() if isinstance(kind, str) else "",
        blocks=raw_blocks.lower(),
        status=raw_status.lower(),
        raw_blocks=raw_blocks,
        raw_status=raw_status,
    )
    options = entry.get("options")
    return {
        "item": item,
        "statement": str(entry.get("statement") or ""),
        "expected_form": str(entry.get("expectedForm") or ""),
        "options": (
            [option for option in options if isinstance(option, dict)]
            if isinstance(options, list)
            else []
        ),
        "disposition": clarification_disposition(entry),
    }


def _v2_clarification_rows(report_path: Path) -> Optional[list[dict]]:
    """schema-v2 clarification 행들, 이 리포트가 v2 가 아니면 ``None``.
    필수 필드가 빠진 행은 건너뛰는 lenient 계약(§1 파서와 동일)."""
    data = _structured_report_data(report_path)
    if data is None:
        return None
    entries = data.get("clarificationItems")
    if not isinstance(entries, list):
        return []
    rows = [_v2_row(e) for e in entries if isinstance(e, dict)]
    return [row for row in rows if row is not None]


def read_clarification_rows(report_path: Path) -> list[dict]:
    """리포트 한 건의 clarification 행 — schema-v2 는 data.json 사이드카에서,
    schema-v1 은 §1 테이블에서. 스키마 버전을 아는 유일한 읽기 지점이다.

    ``parse_section_1_rows`` 와 같은 lenient 계약: 어느 쪽에서도 행을 못 찾으면
    ``[]``.
    """
    v2_rows = _v2_clarification_rows(report_path)
    if v2_rows is not None:
        return v2_rows
    return parse_section_1_rows(_read_report_text(report_path))
