"""materialize 를 요청한 신원이 이 run 이 발급한 것인지 확인한다.

run manifest 는 어떤 role 이 어떤 assignment 로 실행되는지를 이미 적어 두었다.
CLI 인자가 그것과 어긋나면 감사 기록이 실행과 달라지므로 거절한다. 이 검사가
없으면 매니페스트에 없는 role 로 프롬프트를 찍어 낼 수 있다.
"""
from __future__ import annotations

from typing import Any, Mapping

from ...worker_prompt_policy import (
    CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT,
    is_plan_critic_verification,
    resolve_prompt_plan_for_manifest,
)
from .inputs import AgentPromptCliError


def _validate_run_identity(
    manifest: Mapping[str, Any],
    *,
    worker_id: str,
    dispatch_kind: str,
    assignment_ref: str,
    audience: str,
) -> None:
    expected: str
    if assignment_ref == "lead":
        expected = "lead"
        if worker_id != "lead":
            raise AgentPromptCliError("lead assignment requires worker ID 'lead'")
    elif assignment_ref == "translator":
        expected = "translator"
        if worker_id != "translator":
            raise AgentPromptCliError("translator assignment requires worker ID 'translator'")
    elif assignment_ref.startswith("critic/"):
        scope = assignment_ref.split("/", 1)[1]
        expected = CRITIC_DUTY_BY_ASSIGNMENT_SEGMENT.get(scope, "")
        if is_plan_critic_verification(
            task_type=str(manifest.get("taskType", "")),
            assignment_ref=assignment_ref, dispatch_kind=dispatch_kind,
        ):
            expected = "reverification-worker"
        elif not expected or dispatch_kind != "critic":
            raise AgentPromptCliError("critic assignment identity is invalid")
        # provider 대조는 여기 두지 않는다. critic 의 `worker_id` 는 배정 참조의
        # 마지막 마디(`scope` / `acceptance`)이고 provider 이름이 아니다
        # (`render.py` 의 로스터 행이 `assignment_ref.rsplit("/", 1)[-1]` 로 만든다).
        # 종전에 있던 `provider != worker_id` 검사는 두 어휘를 비교해서 늘 참이 되는
        # 형태였고, 설정을 run manifest 에서 찾다 못 찾아 조용히 건너뛰었기에
        # 드러나지 않았다. 정본에서 읽게 고치면 모든 critic 디스패치가 거부된다.
    else:
        try:
            expected = resolve_prompt_plan_for_manifest(
                manifest=manifest,
                worker_id=worker_id,
                dispatch_kind=dispatch_kind,
            ).duty_audience
        except ValueError as exc:
            raise AgentPromptCliError(str(exc)) from exc
        if audience != expected and _manifest_issued_role_execution(
            manifest, audience=audience, assignment_ref=assignment_ref
        ):
            # The prompt plan names a worker's role by worker id, so on an
            # implementation run the executor's provider resolves to the
            # executor role no matter which role execution is being targeted.
            # But the manifest issues one role execution per role, and a
            # provider serving as both executor and verifier gets two — a
            # normal roster, since the verifier contract accepts reusing the
            # executor's model behind its own session. Refusing the second
            # audience made a role execution okstra had itself issued
            # undispatchable, which costs the run an independent verifier.
            expected = audience
    if audience != expected:
        raise AgentPromptCliError(
            f"audience {audience!r} does not match required audience {expected!r}"
        )


def _manifest_issued_role_execution(
    manifest: Mapping[str, Any],
    *,
    audience: str,
    assignment_ref: str,
) -> bool:
    """Whether this run issued a role execution for that audience's role.

    Keyed on the manifest's own rows, not on what the prompt plan infers from
    a worker id: the question is whether okstra created the execution being
    targeted, and only the manifest answers that.
    """
    from ...domain.role import RoleCatalogError, role_for_duty

    try:
        role = role_for_duty(audience)
    except RoleCatalogError:
        return False
    assignments = manifest.get("invocationAssignments")
    assignment = (
        assignments.get(assignment_ref) if isinstance(assignments, Mapping) else None
    )
    provider = (
        assignment.get("provider") if isinstance(assignment, Mapping) else None
    )
    if not provider:
        return False
    executions = manifest.get("roleExecutions")
    return any(
        isinstance(row, Mapping)
        and row.get("role") == role
        and row.get("provider") == provider
        for row in (executions if isinstance(executions, list) else [])
    )
