"""리포트 계약 3.0의 역할별 입력 경로와 단일 소유자 레지스트리."""
from __future__ import annotations

from dataclasses import dataclass
from pathlib import Path
from typing import Any, Mapping


REPORT_CONTRACT_V3 = "3.0"


class ReportInputError(ValueError):
    """3.0 입력 경로나 소유자가 매니페스트에서 해소되지 않았다."""


@dataclass(frozen=True)
class ReportInputPath:
    key: str
    owner: str
    path: Path


_INPUT_FIELDS = (
    ("narrative", "report-writer", "reportNarrativePath"),
    ("approval-decisions", "lead", "approvalDecisionsPath"),
    ("agent-activity", "activity-ledger", "leadEventsPath"),
    ("execution-status", "team-state", "teamStatePath"),
    ("convergence", "convergence", "convergenceStatePath"),
)

_PLANNING_INPUT_FIELDS = (
    ("design-preparation", "design-surface-detector", "designPreparationPath"),
    ("plan-body-verification", "convergence", "planBodyVerificationPath"),
)


def uses_report_contract_v3(manifest: Mapping[str, Any]) -> bool:
    return str(manifest.get("reportContractVersion") or "").strip() == REPORT_CONTRACT_V3


def _project_path(project_root: Path, value: object, field: str) -> Path:
    if not isinstance(value, str) or not value.strip():
        raise ReportInputError(f"report contract 3.0 requires {field}")
    path = Path(value)
    return path if path.is_absolute() else project_root / path


def report_narrative_path(
    project_root: Path, manifest: Mapping[str, Any],
) -> Path:
    if not uses_report_contract_v3(manifest):
        raise ReportInputError("report narrative path belongs to report contract 3.0")
    return _project_path(project_root, manifest.get("reportNarrativePath"), "reportNarrativePath")


def report_input_paths(
    project_root: Path, manifest: Mapping[str, Any],
) -> tuple[ReportInputPath, ...]:
    if not uses_report_contract_v3(manifest):
        raise ReportInputError("role-owned report inputs require report contract 3.0")
    fields = _INPUT_FIELDS + (
        _PLANNING_INPUT_FIELDS
        if manifest.get("taskType") == "implementation-planning"
        else ()
    )
    rows = tuple(
        ReportInputPath(key, owner, _project_path(project_root, manifest.get(field), field))
        for key, owner, field in fields
    )
    if len({row.key for row in rows}) != len(rows):
        raise ReportInputError("report input keys must be unique")
    return rows
