"""Build the shared capability-bundle matrix for the Home marketing corpus.

Pages are grouped by the admitted App Blocks and backend packs they need.
Primitive requirements are read from the canonical manifests/contracts so this
artifact can drive Core, Cloud, and Dash work without inventing per-page APIs.
"""

from __future__ import annotations

import json
from collections import defaultdict
from pathlib import Path

from scripts.harvest_marketing_product_coverage import harvest
from src.domain.app_blocks.job_packs import get_job_pack
from src.domain.app_blocks.registry import load_default_registry
from src.domain.feature_packs.normalize import load_pack_contract

ROOT = Path(__file__).resolve().parents[1]
OUT = ROOT / "docs/coverage/MARKETING_CAPABILITY_MATRIX.json"


def build_matrix() -> dict:
    coverage = harvest()
    registry = load_default_registry()
    manifests = {manifest.id: manifest for manifest in registry.all()}
    bundles: dict[tuple, dict] = {}
    pages_by_bundle: defaultdict[tuple, list[str]] = defaultdict(list)

    for row in coverage["pages"]:
        blocks = tuple(sorted(row["app_blocks"]))
        job_pack_ids = tuple(sorted(row.get("job_feature_packs") or []))
        packs_set = set(row["feature_packs"])
        for job_pack_id in job_pack_ids:
            job_pack = get_job_pack(job_pack_id)
            if job_pack is None:
                raise ValueError(f"unknown job feature pack {job_pack_id!r} for {row['slug']}")
            packs_set.update(job_pack.required_backend_packs)
        packs = tuple(sorted(packs_set))
        primitive_ids: set[str] = set()
        providers: set[str] = set()
        for block_id in blocks:
            manifest = manifests[block_id]
            primitive_ids.update(
                requirement.id
                for requirement in manifest.requires
                if requirement.kind == "primitive"
            )
        for pack in packs:
            contract = load_pack_contract(pack, {})
            primitive_ids.update(contract.required_primitive_ids())
            providers.update(contract.configuration_providers())
        key = (
            blocks,
            packs,
            job_pack_ids,
            tuple(sorted(primitive_ids)),
            tuple(sorted(providers)),
            # Readiness is part of the backend composition contract. Pages
            # with identical UI blocks can still require different admitted
            # architecture decisions or provider configuration, so do not
            # merge those pages into one misleading bundle.
            tuple(sorted(row.get("gaps") or [])),
            tuple(sorted(row.get("mismatches") or [])),
        )
        pages_by_bundle[key].append(row["slug"])
        bundles.setdefault(
            key,
            {
                "app_blocks": list(blocks),
                "feature_packs": list(packs),
                "job_feature_packs": list(job_pack_ids),
                "primitive_ids": sorted(primitive_ids),
                "configuration_providers": sorted(providers),
            },
        )

    ordered = []
    for index, (key, bundle) in enumerate(
        sorted(bundles.items(), key=lambda item: (item[0][0], item[0][1]))
    ):
        bundle["bundle_id"] = f"bundle_{index + 1:03d}"
        bundle["pages"] = sorted(pages_by_bundle[key])
        bundle["page_count"] = len(bundle["pages"])
        ordered.append(bundle)

    return {
        "schema_version": 1,
        "source": "P2HS-Home/scripts/market-pages.js",
        "page_count": coverage["page_count"],
        "bundle_count": len(ordered),
        "bundles": ordered,
    }


def main() -> int:
    payload = build_matrix()
    OUT.parent.mkdir(parents=True, exist_ok=True)
    OUT.write_text(json.dumps(payload, indent=2) + "\n", encoding="utf-8")
    print(f"wrote {OUT} pages={payload['page_count']} bundles={payload['bundle_count']}")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())
