"""Read-only Phase 5C canonical metadata evidence inventory."""

from __future__ import annotations

import asyncio
import hashlib
import json
import subprocess
from collections import Counter
from pathlib import Path
from typing import Any

from dotenv import dotenv_values
from sqlalchemy import text
from sqlalchemy.ext.asyncio import create_async_engine


ROOT = Path(__file__).parents[1]
CLONES = Path(r"C:\Users\Mohsin.Abbas\AppData\Local\Temp\p2hs-phase5a-e5220a3312ca4c9bb6ee8d8c17bca1ea")


def digest(value: Any) -> str:
    encoded = json.dumps(value, sort_keys=True, separators=(",", ":"), default=str).encode()
    return hashlib.sha256(encoded).hexdigest()


def repo_for(project_id: str) -> Path:
    return CLONES / f"p2hs-{project_id.replace('-', '')}"


def artifact_evidence(project_id: str) -> dict[str, Any]:
    repo = repo_for(project_id)
    files = {}
    for name in ("p2hs/app-recipe.json", "p2hs/app-blocks-plan.json", "p2hs/generation-plan.json", "p2hs/core-composition.json", "p2hs/feature-packs.json"):
        path = repo / name
        entry: dict[str, Any] = {"present": path.is_file(), "platform_owned": False, "unmodified": False, "schema_version": None, "sha256": None}
        if path.is_file():
            raw = path.read_bytes()
            entry["sha256"] = hashlib.sha256(raw).hexdigest()
            try:
                payload = json.loads(raw)
                entry["schema_version"] = payload.get("schema_version") or payload.get("version")
            except (UnicodeDecodeError, json.JSONDecodeError):
                entry["schema_version"] = "invalid_json"
            try:
                tracked = subprocess.run(["git", "ls-files", "--error-unmatch", name], cwd=repo, capture_output=True, text=True, check=False)
                status = subprocess.run(["git", "status", "--porcelain", "--", name], cwd=repo, capture_output=True, text=True, check=False)
                entry["platform_owned"] = tracked.returncode == 0
                entry["unmodified"] = not status.stdout.strip()
            except OSError:
                pass
        files[name] = entry
    return files


def component_state(project: dict[str, Any], runs: list[dict[str, Any]], packs: list[dict[str, Any]], artifacts: dict[str, Any]) -> dict[str, Any]:
    snapshot = project["snapshot"]
    plan_candidates = [run["plan"] for run in runs if isinstance(run.get("plan"), dict) and isinstance(run["plan"].get("composition"), dict)]
    plan = plan_candidates[-1] if plan_candidates else None
    recipe = (plan or {}).get("composition", {}).get("recipe_ids") or []
    starter = (plan or {}).get("composition", {}).get("starter_id")
    generation_plan = artifacts["p2hs/generation-plan.json"]
    locked_generation = bool(generation_plan["present"] and generation_plan["platform_owned"] and generation_plan["unmodified"] and generation_plan["schema_version"] == "generation_plan.v1")
    has_integrity = locked_generation and bool(generation_plan.get("sha256"))
    return {
        "snapshot": "EXACT_RECORDED" if snapshot else "UNRECOVERABLE",
        "recipe": "EXACT_RECORDED" if recipe else ("ARTIFACT_ATTESTED" if artifacts["p2hs/app-recipe.json"]["present"] else "UNRECOVERABLE"),
        "starter": "EXACT_RECORDED" if starter else ("ARTIFACT_ATTESTED" if artifacts["p2hs/app-recipe.json"]["present"] else "UNRECOVERABLE"),
        "feature_packs": "EXACT_RECORDED" if packs or (plan and isinstance((plan.get("composition") or {}).get("feature_pack_ids"), list)) else "UNRECOVERABLE",
        "app_blocks": "EXACT_RECORDED" if plan and isinstance((plan.get("composition") or {}).get("app_block_ids"), list) else ("ARTIFACT_ATTESTED" if artifacts["p2hs/app-blocks-plan.json"]["present"] else "UNRECOVERABLE"),
        "generation_plan": "ARTIFACT_ATTESTED" if has_integrity else ("EXACT_RECORDED" if plan and (plan.get("provenance") or {}).get("plan_hash") else "UNRECOVERABLE"),
        "artifact_integrity": "PLATFORM_OWNED_INTACT_HASH_PRESENT" if has_integrity else "INSUFFICIENT_INTEGRITY_EVIDENCE",
        "auth": "BLOCKED_PHASE_5D" if project["auth_enabled"] else "UNRESOLVED_NOT_REQUIRED",
    }


async def main() -> None:
    env = dotenv_values(ROOT / ".env")
    engine = create_async_engine(str(env["DATABASE_URL"]), pool_pre_ping=True)
    async with engine.connect() as db:
        rows = (await db.execute(text("""
            SELECT p.id::text AS id, p.workspace_id::text AS workspace_id, p.status::text AS status,
                   p.type::text AS type, p.source_kind, p.discovery_json, p.runtime_invariants,
                   p.source_repo_full_name, p.platform_files_version,
                   EXISTS (SELECT 1 FROM installed_composition_snapshots s WHERE s.project_id=p.id) AS has_snapshot,
                   EXISTS (SELECT 1 FROM project_auth_config a WHERE a.project_id=p.id AND a.enabled=true) AS auth_enabled
            FROM projects p WHERE p.deleted_at IS NULL ORDER BY p.id
        """))).mappings().all()
        project_ids = [row["id"] for row in rows]
        runs_rows = (await db.execute(text("SELECT project_id::text AS project_id, plan, status::text AS status FROM codegen_runs WHERE project_id = ANY(:ids) ORDER BY created_at"), {"ids": project_ids})).mappings().all()
        pack_rows = (await db.execute(text("SELECT project_id::text AS project_id, pack_slug, pack_version, status FROM project_feature_packs WHERE project_id = ANY(:ids)"), {"ids": project_ids})).mappings().all()
    await engine.dispose()

    by_runs: dict[str, list[dict[str, Any]]] = {}
    by_packs: dict[str, list[dict[str, Any]]] = {}
    for row in runs_rows: by_runs.setdefault(row["project_id"], []).append(dict(row))
    for row in pack_rows: by_packs.setdefault(row["project_id"], []).append(dict(row))

    records = []
    for row in rows:
        project = dict(row)
        project["snapshot"] = bool(project.pop("has_snapshot"))
        artifacts = artifact_evidence(project["id"])
        components = component_state(project, by_runs.get(project["id"], []), by_packs.get(project["id"], []), artifacts)
        required = [components[name] for name in ("recipe", "starter", "feature_packs", "app_blocks", "generation_plan")]
        if project["source_kind"] != "generated":
            primary = "NOT_APPLICABLE"
            reason = "non_generated_source_kind"
        elif project["snapshot"] and all(value == "EXACT_RECORDED" for value in required):
            primary = "ELIGIBLE"
            reason = "complete_recorded_baseline"
        elif all(value == "EXACT_RECORDED" for value in required) and components["auth"] != "BLOCKED_PHASE_5D":
            primary = "ELIGIBLE"
            reason = "complete_deterministic_baseline"
        elif any(value != "UNRECOVERABLE" for value in required):
            primary = "PARTIAL"
            reason = "some_components_deterministic_but_baseline_incomplete"
        else:
            primary = "INELIGIBLE_INSUFFICIENT_EVIDENCE"
            reason = "required_baseline_evidence_missing"
        records.append({"project_id": project["id"], "status": project["status"], "type": project["type"], "source_kind": project["source_kind"], "primary_disposition": primary, "primary_reason": reason, "components": components, "artifacts": artifacts, "run_count": len(by_runs.get(project["id"], [])), "pack_count": len(by_packs.get(project["id"], [])), "semantic_component_fingerprint": digest({"components": components}), "binding_scope_fingerprint": digest({"project_id": project["id"], "workspace_id": project["workspace_id"], "source_kind": project["source_kind"]})})

    counts = Counter(record["primary_disposition"] for record in records)
    assert sum(counts.values()) == len(records) == 67
    artifact_counts = {name: {"present": sum(item["artifacts"][name]["present"] for item in records), "platform_owned_intact": sum(item["artifacts"][name]["platform_owned"] and item["artifacts"][name]["unmodified"] for item in records)} for name in records[0]["artifacts"]}
    output = {"population": len(records), "primary_disposition_counts": dict(sorted(counts.items())), "artifact_counts": artifact_counts, "records": records}
    print(json.dumps(output, sort_keys=True, separators=(",", ":")))


if __name__ == "__main__":
    asyncio.run(main())
