"""종결된 호출의 결과를 보존하는 증거 보완 프롬프트 발행."""
from __future__ import annotations

from pathlib import Path

from .invocation import (
    AgentInstruction, AgentInstructionSource, AgentInvocationError,
    AgentInvocationRequest, PreparedAgentInvocation, _extract_anchor_lines,
    _split_prompt, agent_model_assignment_from_payload, invocation_metadata_identity,
    prepare_agent_invocation, verify_agent_invocation,
)
from ..json_boundary import load_owned_object
from ..worker_artifact_paths import audit_sidecar_rel


def prepare_evidence_recovery(
    metadata_path: Path, *, project_root: Path, result_path: Path,
    source_attempt: int,
) -> tuple[PreparedAgentInvocation, Path]:
    """원래 모델·역할을 유지하고 새 결과 경로에 제한된 증거 보완을 발행한다."""
    metadata = load_owned_object(metadata_path, artifact="recovery source metadata")
    source = metadata["contractSource"]
    manifest = project_root / source["runManifestPath"]
    errors = verify_agent_invocation(
        metadata_path, project_root=project_root, expected_run_manifest_path=manifest,
    )
    if errors:
        raise AgentInvocationError("invalid recovery source: " + "; ".join(errors))
    identity = invocation_metadata_identity(metadata)
    if identity is None or not result_path.is_file():
        raise AgentInvocationError("evidence recovery requires v2 identity and an existing result")
    suffix = f"-evidence-recovery-{source_attempt}"
    invocation_id = identity.invocation_ref + suffix
    old_prompt = project_root / metadata["prompt"]["path"]
    prompt = old_prompt.with_name(old_prompt.stem + suffix + old_prompt.suffix)
    result = result_path.with_name(result_path.name.replace("-worker-", suffix + "-worker-", 1))
    prefix, _ = _split_prompt(old_prompt.read_text(encoding="utf-8"))
    replacements = {
        "**Prompt History Path:**": str(prompt.relative_to(project_root)),
        "Assigned worker prompt history path:": str(prompt),
        "**Result Path:**": str(result.relative_to(project_root)),
        "**Worker Result Path:**": str(result.relative_to(project_root)),
        "**Audit sidecar path:**": audit_sidecar_rel(str(result)),
    }
    anchors = tuple(next((f"{key} {value}" for key, value in replacements.items()
                          if line.startswith(key)), line) for line in _extract_anchor_lines(prefix))
    body = _recovery_instructions(identity.invocation_ref, source_attempt, result_path, old_prompt)
    prepared = prepare_agent_invocation(AgentInvocationRequest(
        invocation_id=invocation_id, worker_id=None, audience=metadata["audience"],
        assignment_ref=metadata["assignmentRef"], purpose=None,
        assignment=agent_model_assignment_from_payload(metadata["modelAssignment"]),
        instruction=AgentInstruction(anchor_lines=anchors, body=body, source_paths=(
            AgentInstructionSource("project", str(result_path.relative_to(project_root))),)),
        project_root=project_root, run_manifest_path=manifest,
        duty_root=project_root / source["dutyRootPath"], prompt_path=prompt,
        metadata_path=prompt.with_name(prompt.name + ".meta.json"),
        dispatch_kind=metadata["dispatchKind"], participant_ref=identity.participant_ref,
        role_execution_ref=identity.role_execution_ref, duty_id=identity.duty_id,
        invocation_ref=invocation_id, attempt=1,
    ))
    return prepared, result


def _recovery_instructions(invocation_ref: str, source_attempt: int, result_path: Path, old_prompt: Path) -> str:
    """완료된 구현을 재실행하지 않는 보완 범위를 전달한다."""
    return (
        "## Evidence recovery scope\n\n"
        f"Original invocation: {invocation_ref}; attempt: {source_attempt}.\n"
        f"Read and preserve the original result: {result_path}.\n"
        f"Read the original audit: {old_prompt}.mutation-audit.json.\n"
        "The prior attempt failed only on a declaration discrepancy. Preserve existing source and QA work. "
        "Do not repeat completed implementation steps or edit production source. Reconcile the declaration "
        "and required evidence against current artifacts; retain historical validation as historical. "
        "Do not invent a missing before-state or claim independent verification. If a substantive defect "
        "or authority problem is found, report it for the lead instead of expanding this repair. "
        "Write a new completion result in the original role's required format, citing the original result "
        "and clearly separating recovered evidence from remaining independent checks.\n"
    )
