"""validate-tasks-04 — 셸 시나리오에서 꺼낸 단언 블록.

호출부: validators/lib/validate-tasks.sh:44
규칙 R1 은 실행될 소스를 문자열/heredoc 이 아니라 실파일에 두게 한다.
이 파일의 내용은 꺼내기 전과 같다 — 옮기기만 했다.
"""
from pathlib import Path
import json
import sys

project_root = Path(sys.argv[1])
catalog_path = Path(sys.argv[2])
expected_latest_task_key = sys.argv[3]
expected_latest_task_relative_path = sys.argv[4]
expected_task_keys = sys.argv[5:]
errors = []

if not catalog_path.is_file():
    errors.append(f"task catalog is missing: {catalog_path}")
else:
    catalog = json.loads(catalog_path.read_text())
    tasks = catalog.get("tasks", [])

    if catalog.get("latestTaskKey") != expected_latest_task_key:
        errors.append("task catalog does not record the expected latestTaskKey")

    if catalog.get("latestTaskDiscoveryPath") != expected_latest_task_relative_path:
        errors.append("task catalog does not expose latestTaskDiscoveryPath")

    if catalog.get("taskCount") != len(expected_task_keys):
        errors.append("task catalog taskCount does not match the expected number of tasks")

    if not isinstance(tasks, list):
        errors.append("task catalog tasks entry is not a list")
    else:
        catalog_by_key = {}
        for entry in tasks:
            if not isinstance(entry, dict):
                errors.append("task catalog contains a non-object entry")
                continue
            task_key = entry.get("taskKey", "")
            if not task_key:
                errors.append("task catalog contains an entry without taskKey")
                continue
            if task_key in catalog_by_key:
                errors.append(f"task catalog contains a duplicate task key: {task_key}")
                continue
            catalog_by_key[task_key] = entry

        for expected_task_key in expected_task_keys:
            entry = catalog_by_key.get(expected_task_key)
            if entry is None:
                errors.append(f"task catalog is missing task key: {expected_task_key}")
                continue
            task_key_parts = expected_task_key.split(":", 2)
            if len(task_key_parts) != 3:
                errors.append(f"expected task key is malformed: {expected_task_key}")
                continue
            _, expected_task_group, expected_task_id = task_key_parts

            if entry.get("taskGroup") != expected_task_group:
                errors.append(f"task catalog entry is missing the expected taskGroup: {expected_task_key}")

            if entry.get("taskId") != expected_task_id:
                errors.append(f"task catalog entry is missing the expected taskId: {expected_task_key}")

            task_manifest_relative_path = entry.get("taskManifestPath", "")
            if not task_manifest_relative_path:
                errors.append(f"task catalog entry is missing taskManifestPath: {expected_task_key}")
            else:
                task_manifest_path = project_root / task_manifest_relative_path
                if not task_manifest_path.is_file():
                    errors.append(f"task catalog points to a missing task manifest: {task_manifest_path}")

            reference_relative_path = entry.get("referenceExpectationsPath", "")
            if not reference_relative_path:
                errors.append(
                    f"task catalog entry is missing referenceExpectationsPath: {expected_task_key}"
                )
            else:
                reference_path = project_root / reference_relative_path
                if not reference_path.is_file():
                    errors.append(
                        f"task catalog points to a missing reference expectations file: {reference_path}"
                    )

            latest_run_manifest_relative_path = entry.get("latestRunManifestPath", "")
            if not latest_run_manifest_relative_path:
                errors.append(
                    f"task catalog entry is missing latestRunManifestPath: {expected_task_key}"
                )
            else:
                latest_run_manifest_path = project_root / latest_run_manifest_relative_path
                if not latest_run_manifest_path.is_file():
                    errors.append(
                        f"task catalog points to a missing latest run manifest: {latest_run_manifest_path}"
                    )
                else:
                    run_manifest = json.loads(latest_run_manifest_path.read_text())
                    latest_run_prompts_relative_path = entry.get(
                        "latestRunPromptsPath", ""
                    )
                    if not latest_run_prompts_relative_path:
                        errors.append(
                            f"task catalog entry is missing latestRunPromptsPath: {expected_task_key}"
                        )
                    elif (
                        run_manifest.get("workerPromptsDirectoryPath")
                        != latest_run_prompts_relative_path
                    ):
                        errors.append(
                            f"task catalog entry latestRunPromptsPath does not match the latest run manifest: {expected_task_key}"
                        )

if errors:
    for error in errors:
        print(error, file=sys.stderr)
    sys.exit(1)
