"""Build UI catalog / method payloads from OpenStack contract packs."""

from __future__ import annotations

import re
from typing import Any

from app.contracts.examples import path_param_example
from app.openstack.contract_loader import (
    ensure_loaded,
    load_series_pack,
    major_for_series,
    series_for_major,
)

_PATH_PARAM = re.compile(r"\{([^{}]+)\}")


def openstack_catalog_payload(major: int) -> dict[str, Any]:
    series = series_for_major(major)
    ensure_loaded(series)
    packs = load_series_pack(series)
    categories: list[dict[str, Any]] = []
    path_count = 0
    method_count = 0
    for name, pack in sorted(packs.items(), key=lambda item: item[0]):
        by_path: dict[str, list[dict[str, Any]]] = {}
        for op in pack.operations:
            by_path.setdefault(op.path, []).append(
                {
                    "verb": op.method,
                    "name": op.operation_id,
                    "description": op.notes or f"{op.kind} {op.resource_type}",
                    "protected": op.requires_auth,
                    "implemented": True,
                }
            )
        paths = [
            {"path": path, "methods": methods}
            for path, methods in sorted(by_path.items(), key=lambda item: item[0])
        ]
        path_count += len(paths)
        method_count += sum(len(item["methods"]) for item in paths)
        categories.append({"tag": name, "paths": paths})
    return {
        "major": major,
        "series": {
            "yoga": "Yoga",
            "antelope": "Antelope",
            "caracal": "Caracal",
            "dalmatian": "Dalmatian",
        }.get(series, series.title()),
        "source_version": f"openstack-{series}",
        "latest_version": series,
        "artifact_url": f"contracts/openstack/{series}",
        "bundled": True,
        "path_count": path_count,
        "method_count": method_count,
        "categories": categories,
        "catalog_kind": "openstack",
    }


def openstack_method_payload(
    *,
    major: int,
    path: str,
    verb: str,
    runtime_version: str | None,
) -> dict[str, Any]:
    series = series_for_major(major)
    packs = load_series_pack(series)
    verb_u = verb.upper()
    for pack in packs.values():
        for op in pack.operations:
            if op.path == path and op.method == verb_u:
                path_params = _PATH_PARAM.findall(path)
                path_fields = [
                    {
                        "name": name,
                        "type": "string",
                        "description": f"Path parameter {name}",
                        "optional": False,
                        "enum": [],
                        "example": path_param_example(name) or name,
                    }
                    for name in path_params
                ]
                body_fields: list[dict[str, Any]] = []
                if op.method in {"POST", "PUT", "PATCH"} and op.kind in {
                    "collection",
                    "item",
                    "action",
                    "custom",
                }:
                    key = op.item_key or op.collection_key or "resource"
                    body_fields.append(
                        {
                            "name": key,
                            "type": "object",
                            "description": "Request body envelope",
                            "optional": op.kind == "action",
                            "enum": [],
                            "example": {key: {"name": "example"}}
                            if op.kind != "action"
                            else {op.action_name or "os-start": None},
                        }
                    )
                return {
                    "major": major,
                    "series": series,
                    "path": path,
                    "verb": verb_u,
                    "name": op.operation_id,
                    "description": op.notes or f"{pack.name} {op.resource_type}",
                    "protected": op.requires_auth,
                    "implemented": True,
                    "runtime_version": runtime_version,
                    "path_fields": path_fields,
                    "query_fields": [
                        {
                            "name": "limit",
                            "type": "integer",
                            "description": "Max items",
                            "optional": True,
                            "enum": [],
                            "example": 25,
                        },
                        {
                            "name": "marker",
                            "type": "string",
                            "description": "Pagination marker (id)",
                            "optional": True,
                            "enum": [],
                            "example": "",
                        },
                    ]
                    if op.method == "GET" and op.kind in {"collection", "detail"}
                    else [],
                    "body_fields": body_fields,
                    "returns": {"type": "object"},
                    "permissions": [],
                    "service": pack.name,
                    "port": pack.port,
                }
    raise KeyError(f"{verb} {path}")


def openstack_series_majors(runtime_version: str | None = None) -> dict[str, object]:
    from app.openstack.contract_loader import list_series

    series = list_series()
    return {
        "runtime_version": runtime_version,
        "majors": [
            {
                "major": item["major"],
                "series": str(item["series"]).title(),
                "latest_version": item["series"],
                "artifact_url": f"contracts/openstack/{item['series']}",
                "bundled": True,
                "operation_count": item["operation_count"],
            }
            for item in sorted(series, key=lambda row: row["major"])
        ],
    }


def openstack_compatibility_payload(
    major: int,
    *,
    runtime_version: str | None = None,
    schema_ops_mounted: int | None = None,
) -> dict[str, Any]:
    """Compatibility summary from OpenStack pack ops (surface-complete packs)."""

    series = series_for_major(major)
    packs = load_series_pack(series)
    # Count every pack operation (same basis as pack operation_count). Path+/verb
    # alone is not unique across services (e.g. GET /v1).
    method_names: list[str] = []
    groups: dict[str, dict[str, int]] = {}
    for name, pack in sorted(packs.items(), key=lambda item: item[0]):
        counters = groups.setdefault(name, {"declared": 0, "implemented": 0, "verified": 0})
        for op in pack.operations:
            method_names.append(f"{op.method.upper()} [{name}] {op.path}")
            counters["declared"] += 1
            # Pack operations are mounted via specialized routers + schema engine.
            counters["implemented"] += 1

    method_names.sort()
    total = len(method_names)
    score = 1.0 if total else 1.0
    mounted = schema_ops_mounted if schema_ops_mounted is not None else total

    methods_by_verb: dict[str, int] = {}
    for name, pack in packs.items():
        _ = name
        for op in pack.operations:
            verb = op.method.upper()
            methods_by_verb[verb] = methods_by_verb.get(verb, 0) + 1

    def _level(count: int, methods: list[str] | None = None) -> dict[str, Any]:
        return {
            "count": count,
            "score": (count / total) if total else 1.0,
            "methods": methods if methods is not None else [],
        }

    # Compact method samples for UI (full list is large).
    sample = method_names[:40]

    return {
        "source_version": f"openstack-{series}",
        "catalog_version": f"openstack-{series}",
        "latest_version": series,
        "major": major,
        "series": series,
        "catalog_kind": "openstack",
        "runtime_version": runtime_version or f"openstack-{series}",
        "evidence_scope": "catalog",
        "total_declared": total,
        "schema_ops_mounted": mounted,
        "service_count": len(packs),
        "methods_by_verb": dict(sorted(methods_by_verb.items())),
        "levels": {
            "declared": _level(total, sample),
            "schema_only": _level(0),
            "implemented": _level(total, sample),
            "observed": _level(0),
            "verified": _level(0),
        },
        "groups": dict(sorted(groups.items())),
        "dimension_groups": {},
        "classifications": {
            # Store counts only — length of full method lists is expensive in the UI.
            "fully_compatible_count": total,
            "partially_compatible_count": 0,
            "incompatible_count": 0,
            "regressions_count": 0,
            "unsupported_count": 0,
            "fully_compatible": [],
            "partially_compatible": [],
            "incompatible": [],
            "regressions": [],
            "unsupported": [],
        },
        "dimensions": {
            "route_method": {
                "count": total,
                "score": score,
                "methods": sample,
            }
        },
    }


# silence unused import warning helpers
_ = major_for_series
