#!/usr/bin/env python3
"""Show ready and pending Zo image tools jobs for a Zo pet run."""

from __future__ import annotations

import argparse
import json
from pathlib import Path


def load_manifest(run_dir: Path) -> dict[str, object]:
    path = run_dir / "zo-image-jobs.json"
    if not path.exists():
        raise SystemExit(f"job manifest not found: {path}")
    return json.loads(path.read_text(encoding="utf-8"))


def jobs(manifest: dict[str, object]) -> list[dict[str, object]]:
    raw = manifest.get("jobs")
    if not isinstance(raw, list):
        raise SystemExit("invalid zo-image-jobs.json: jobs must be a list")
    return [job for job in raw if isinstance(job, dict)]


def completed_ids(manifest: dict[str, object]) -> set[str]:
    return {
        str(job["id"])
        for job in jobs(manifest)
        if job.get("status") == "complete" and isinstance(job.get("id"), str)
    }


def missing_deps(job: dict[str, object], completed: set[str]) -> list[str]:
    deps = job.get("depends_on", [])
    if not isinstance(deps, list):
        return []
    return [dep for dep in deps if isinstance(dep, str) and dep not in completed]


def job_view(
    job: dict[str, object], run_dir: Path, completed: set[str]
) -> dict[str, object]:
    prompt_file = job.get("prompt_file")
    output_path = job.get("output_path")
    inputs = (
        job.get("input_images") if isinstance(job.get("input_images"), list) else []
    )
    input_images = []
    for item in inputs:
        path = (
            run_dir / item["path"]
            if isinstance(item, dict) and isinstance(item.get("path"), str)
            else None
        )
        input_images.append(
            {
                "path": str(path) if path else None,
                "role": item.get("role") if isinstance(item, dict) else None,
                "exists": path.is_file() if path else False,
            }
        )
    return {
        "id": job.get("id"),
        "kind": job.get("kind"),
        "status": job.get("status", "pending"),
        "prompt_file": str(run_dir / prompt_file)
        if isinstance(prompt_file, str)
        else None,
        "input_images": input_images,
        "output_path": str(run_dir / output_path)
        if isinstance(output_path, str)
        else None,
        "missing_dependencies": missing_deps(job, completed),
        "repair_attempt": job.get("repair_attempt", 0),
        "generation_skill": job.get("generation_skill"),
        "requires_grounded_generation": job.get("requires_grounded_generation", False),
        "allow_prompt_only_generation": job.get("allow_prompt_only_generation", False),
        "identity_reference_paths": job.get("identity_reference_paths", []),
        "mirror_policy": job.get("mirror_policy", {}),
        "derived_from": job.get("derived_from"),
        "source_provenance": job.get("source_provenance"),
        "mirror_decision": job.get("mirror_decision"),
        "recording_owner": job.get("recording_owner", "parent"),
    }


def main() -> None:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument("--run-dir", required=True)
    args = parser.parse_args()

    run_dir = Path(args.run_dir).expanduser().resolve()
    manifest = load_manifest(run_dir)
    completed = completed_ids(manifest)
    pending = [
        job for job in jobs(manifest) if job.get("status", "pending") != "complete"
    ]
    ready = [job for job in pending if not missing_deps(job, completed)]
    blocked = [job for job in pending if missing_deps(job, completed)]

    result = {
        "ok": True,
        "run_dir": str(run_dir),
        "counts": {
            "total": len(jobs(manifest)),
            "complete": len(completed),
            "ready": len(ready),
            "blocked": len(blocked),
        },
        "ready_jobs": [job_view(job, run_dir, completed) for job in ready],
        "blocked_jobs": [job_view(job, run_dir, completed) for job in blocked],
    }
    print(json.dumps(result, indent=2))


if __name__ == "__main__":
    main()
