"""Canonical OpenStack service metadata + API-ref-style resource expansions.

Used by generate_packs.py to emit contracts/openstack/<series> packs.
Paths follow OpenStack API-ref conventions (Dalmatian baseline).
"""

from __future__ import annotations

from typing import Any

# name, type, port, version_path, default_mv, max_mv
SERVICES_META: list[tuple[str, str, int, str, str | None, str | None]] = [
    ("keystone", "identity", 5000, "/v3/", None, None),
    ("nova", "compute", 8774, "/v2.1/", "2.1", "2.96"),
    ("neutron", "network", 9696, "/v2.0/", None, None),
    ("glance", "image", 9292, "/v2/", None, None),
    ("cinder", "volumev3", 8776, "/v3/", "3.0", "3.70"),
    ("placement", "placement", 8003, "/", "1.0", "1.39"),
    ("heat", "orchestration", 8004, "/v1/", None, None),
    ("heat-cfn", "cloudformation", 8000, "/v1/", None, None),
    ("swift", "object-store", 8080, "/v1/", None, None),
    ("ironic", "baremetal", 6385, "/", "1.1", "1.90"),
    ("octavia", "load-balancer", 9876, "/v2/", None, None),
    ("barbican", "key-manager", 9311, "/v1/", None, None),
    ("manila", "sharev2", 8786, "/v2/", "2.0", "2.82"),
    ("designate", "dns", 9001, "/v2/", None, None),
    ("magnum", "container-infra", 9511, "/v1/", None, None),
    ("zun", "container", 9517, "/v1/", None, None),
    ("trove", "database", 8779, "/v1.0/", None, None),
    ("mistral", "workflowv2", 8989, "/v2/", None, None),
    ("aodh", "alarming", 8042, "/v2/", None, None),
    ("cloudkitty", "rating", 8889, "/v1/", None, None),
    ("freezer", "backup", 9090, "/v2/", None, None),
    ("blazar", "reservation", 1234, "/v1/", None, None),
    ("vitrage", "rca", 8999, "/", None, None),
    ("masakari", "instance-ha", 15868, "/v1/", None, None),
    ("tacker", "nfv-orchestration", 9890, "/", None, None),
    ("adjutant", "admin-logic", 5050, "/", None, None),
    # Present on docs.openstack.org/2024.2/api (Dalmatian) index.
    ("watcher", "infra-optim", 9322, "/v1/", None, None),
    ("zaqar", "messaging", 8888, "/v2/", None, None),
]

SERIES: list[tuple[str, int]] = [
    ("yoga", 6),
    ("antelope", 7),
    ("caracal", 8),
    ("dalmatian", 9),
]


def _crud(
    resource: str,
    path: str,
    key: str,
    *,
    detail: bool = True,
    actions: list[str] | None = None,
    nested: list[tuple[str, str, str]] | None = None,
) -> list[dict[str, Any]]:
    """Expand a resource into list/detail/create/show/update/delete + actions/nested."""

    singular = key[:-1] if key.endswith("s") and not key.endswith("ss") else key
    if key.endswith("ies"):
        singular = key[:-3] + "y"
    ops: list[dict[str, Any]] = [
        {
            "operation_id": f"{resource}_list",
            "method": "GET",
            "path": path,
            "resource_type": resource,
            "collection_key": key,
            "kind": "collection",
            "status_code": 200,
        },
        {
            "operation_id": f"{resource}_create",
            "method": "POST",
            "path": path,
            "resource_type": resource,
            "collection_key": key,
            "item_key": singular,
            "kind": "collection",
            "status_code": 201,
            "create_status": 201,
        },
        {
            "operation_id": f"{resource}_show",
            "method": "GET",
            "path": f"{path}/{{id}}",
            "resource_type": resource,
            "collection_key": key,
            "item_key": singular,
            "kind": "item",
            "status_code": 200,
        },
        {
            "operation_id": f"{resource}_update",
            "method": "PUT",
            "path": f"{path}/{{id}}",
            "resource_type": resource,
            "collection_key": key,
            "item_key": singular,
            "kind": "item",
            "status_code": 200,
        },
        {
            "operation_id": f"{resource}_patch",
            "method": "PATCH",
            "path": f"{path}/{{id}}",
            "resource_type": resource,
            "collection_key": key,
            "item_key": singular,
            "kind": "item",
            "status_code": 200,
        },
        {
            "operation_id": f"{resource}_delete",
            "method": "DELETE",
            "path": f"{path}/{{id}}",
            "resource_type": resource,
            "collection_key": key,
            "kind": "item",
            "status_code": 204,
        },
    ]
    if detail:
        ops.append(
            {
                "operation_id": f"{resource}_list_detail",
                "method": "GET",
                "path": f"{path}/detail",
                "resource_type": resource,
                "collection_key": key,
                "kind": "detail",
                "status_code": 200,
            }
        )
    for action in actions or []:
        ops.append(
            {
                "operation_id": f"{resource}_action_{action.replace('-', '_')}",
                "method": "POST",
                "path": f"{path}/{{id}}/action",
                "resource_type": resource,
                "collection_key": key,
                "item_key": singular,
                "kind": "action",
                "action_name": action,
                "status_code": 202,
            }
        )
    # Prefer a single shared action endpoint once; expand only unique action names
    # are stored as metadata — runtime uses one POST .../action route.
    for nested_type, nested_path, nested_key in nested or []:
        ops.extend(_crud(nested_type, nested_path, nested_key, detail=False, actions=None))
    return ops


def _get(
    path: str, op_id: str, resource: str, key: str | None = None, **extra: Any
) -> dict[str, Any]:
    return {
        "operation_id": op_id,
        "method": "GET",
        "path": path,
        "resource_type": resource,
        "collection_key": key,
        "kind": "custom",
        "status_code": 200,
        **extra,
    }


def _post(
    path: str, op_id: str, resource: str, key: str | None = None, status: int = 201, **extra: Any
) -> dict[str, Any]:
    return {
        "operation_id": op_id,
        "method": "POST",
        "path": path,
        "resource_type": resource,
        "collection_key": key,
        "kind": "custom",
        "status_code": status,
        **extra,
    }


def keystone_ops() -> list[dict[str, Any]]:
    ops: list[dict[str, Any]] = [
        _get("/v3", "keystone_v3_root", "version", requires_project=False),
        _post(
            "/v3/auth/tokens",
            "keystone_auth_tokens",
            "token",
            status=201,
            requires_auth=False,
            requires_project=False,
        ),
        _get("/v3/auth/tokens", "keystone_validate_token", "token", requires_project=False),
        _get("/v3/auth/catalog", "keystone_catalog", "catalog", requires_project=False),
    ]
    for res, path, key in [
        ("domain", "/v3/domains", "domains"),
        ("project", "/v3/projects", "projects"),
        ("user", "/v3/users", "users"),
        ("group", "/v3/groups", "groups"),
        ("role", "/v3/roles", "roles"),
        ("region", "/v3/regions", "regions"),
        ("service", "/v3/services", "services"),
        ("endpoint", "/v3/endpoints", "endpoints"),
        ("credential", "/v3/credentials", "credentials"),
        ("policy", "/v3/policies", "policies"),
    ]:
        ops.extend(_crud(res, path, key, detail=False))
    ops.extend(
        _crud(
            "application_credential",
            "/v3/users/{user_id}/application_credentials",
            "application_credentials",
            detail=False,
        )
    )
    ops.extend(
        [
            _get(
                "/v3/role_assignments",
                "keystone_role_assignments",
                "role_assignment",
                "role_assignments",
            ),
            _put(
                "/v3/projects/{project_id}/users/{user_id}/roles/{role_id}",
                "keystone_grant_project_role",
                "role_assignment",
            ),
            _delete_op(
                "/v3/projects/{project_id}/users/{user_id}/roles/{role_id}",
                "keystone_revoke_project_role",
                "role_assignment",
            ),
            _get(
                "/v3/projects/{project_id}/users/{user_id}/roles",
                "keystone_list_project_user_roles",
                "role",
                "roles",
            ),
            _get(
                "/v3/OS-INHERIT/domains/{domain_id}/users/{user_id}/roles",
                "keystone_inherit_roles",
                "role",
                "roles",
            ),
            _get("/v3/limits", "keystone_limits", "limit", "limits"),
            _get(
                "/v3/registered_limits",
                "keystone_registered_limits",
                "registered_limit",
                "registered_limits",
            ),
        ]
    )
    return ops


def _put(path: str, op_id: str, resource: str, key: str | None = None) -> dict[str, Any]:
    return {
        "operation_id": op_id,
        "method": "PUT",
        "path": path,
        "resource_type": resource,
        "collection_key": key,
        "kind": "custom",
        "status_code": 204,
    }


def _delete_op(path: str, op_id: str, resource: str) -> dict[str, Any]:
    return {
        "operation_id": op_id,
        "method": "DELETE",
        "path": path,
        "resource_type": resource,
        "kind": "custom",
        "status_code": 204,
    }


def nova_ops() -> list[dict[str, Any]]:
    server_actions = [
        "os-start",
        "os-stop",
        "reboot",
        "rebuild",
        "resize",
        "confirmResize",
        "revertResize",
        "pause",
        "unpause",
        "suspend",
        "resume",
        "shelve",
        "shelveOffload",
        "unshelve",
        "lock",
        "unlock",
        "rescue",
        "unrescue",
        "createImage",
        "createBackup",
        "addFloatingIp",
        "removeFloatingIp",
        "addSecurityGroup",
        "removeSecurityGroup",
        "changePassword",
        "evacuate",
        "migrate",
        "liveMigrate",
        "resetState",
        "os-getConsoleOutput",
        "os-getVNCConsole",
        "remote-consoles",
        "trigger_crash_dump",
    ]
    ops = _crud(
        "server",
        "/v2.1/servers",
        "servers",
        actions=server_actions,
        nested=[
            (
                "volume_attachment",
                "/v2.1/servers/{server_id}/os-volume_attachments",
                "volumeAttachments",
            ),
            (
                "interface_attachment",
                "/v2.1/servers/{server_id}/os-interface",
                "interfaceAttachments",
            ),
            ("instance_action", "/v2.1/servers/{server_id}/os-instance-actions", "instanceActions"),
            ("server_metadata", "/v2.1/servers/{server_id}/metadata", "metadata"),
            ("server_tag", "/v2.1/servers/{server_id}/tags", "tags"),
            (
                "server_security_group",
                "/v2.1/servers/{server_id}/os-security-groups",
                "security_groups",
            ),
        ],
    )
    # Deduplicate action endpoints to a single POST route (schema engine handles body key)
    ops = [o for o in ops if o.get("kind") != "action"]
    ops.append(
        {
            "operation_id": "server_action",
            "method": "POST",
            "path": "/v2.1/servers/{id}/action",
            "resource_type": "server",
            "collection_key": "servers",
            "kind": "action",
            "status_code": 202,
            "action_name": "*",
        }
    )
    ops.extend(_crud("flavor", "/v2.1/flavors", "flavors"))
    ops.extend(_crud("keypair", "/v2.1/os-keypairs", "keypairs", detail=False))
    # keypairs use name as id
    ops.extend(_crud("aggregate", "/v2.1/os-aggregates", "aggregates", detail=False))
    ops.extend(_crud("server_group", "/v2.1/os-server-groups", "server_groups", detail=False))
    ops.extend(
        [
            _get("/v2.1", "nova_versions", "version", requires_project=False),
            _get("/v2.1/os-hypervisors", "hypervisor_list", "hypervisor", "hypervisors"),
            _get("/v2.1/os-hypervisors/detail", "hypervisor_detail", "hypervisor", "hypervisors"),
            _get("/v2.1/os-hypervisors/{id}", "hypervisor_show", "hypervisor", "hypervisors"),
            _get(
                "/v2.1/os-availability-zone", "az_list", "availability_zone", "availabilityZoneInfo"
            ),
            _get(
                "/v2.1/os-availability-zone/detail",
                "az_detail",
                "availability_zone",
                "availabilityZoneInfo",
            ),
            _get("/v2.1/os-services", "compute_services", "service", "services"),
            _get("/v2.1/limits", "compute_limits", "limit", "limits"),
            _get("/v2.1/os-quota-sets/{id}", "quota_set_show", "quota_set", "quota_set"),
            _put("/v2.1/os-quota-sets/{id}", "quota_set_update", "quota_set", "quota_set"),
            _get("/v2.1/os-quota-sets/{id}/detail", "quota_set_detail", "quota_set", "quota_set"),
            _get("/v2.1/os-migrations", "migrations_list", "migration", "migrations"),
            _get("/v2.1/os-networks", "nova_networks", "network", "networks"),
            _get("/v2.1/os-tenant-networks", "nova_tenant_networks", "network", "networks"),
            _get(
                "/v2.1/os-security-groups",
                "nova_security_groups",
                "security_group",
                "security_groups",
            ),
            _get("/v2.1/os-floating-ips", "nova_floating_ips", "floating_ip", "floating_ips"),
            _get(
                "/v2.1/os-instance_usage_audit_log",
                "instance_usage_audit",
                "instance_usage_audit_log",
                "instance_usage_audit_logs",
            ),
            _get(
                "/v2.1/os-assisted-volume-snapshots",
                "assisted_volume_snapshots",
                "assisted_volume_snapshot",
                "snapshots",
            ),
            _post(
                "/v2.1/os-server-external-events",
                "server_external_events",
                "server_external_event",
                "events",
                status=200,
            ),
            _get("/v2.1/servers/{server_id}/diagnostics", "server_diagnostics", "server"),
            _get(
                "/v2.1/servers/{server_id}/os-instance-actions/{request_id}",
                "instance_action_show",
                "instance_action",
                "instanceAction",
            ),
            _post(
                "/v2.1/servers/{server_id}/remote-consoles",
                "remote_console_create",
                "remote_console",
                "remote_console",
                status=200,
            ),
            _get(
                "/v2.1/flavors/{id}/os-extra_specs",
                "flavor_extra_specs",
                "flavor_extra_spec",
                "extra_specs",
            ),
            _get("/v2.1/os-simple-tenant-usage", "simple_tenant_usage", "usage", "tenant_usages"),
            _get("/v2.1/os-hosts", "os_hosts", "host", "hosts"),
            # Additional Compute API-ref surface (Dalmatian).
            _get("/v2.1/extensions", "nova_extensions", "extension", "extensions"),
            _get("/v2.1/extensions/{id}", "nova_extension_show", "extension"),
            *_crud("agent", "/v2.1/os-agents", "agents", detail=False),
            *_crud(
                "flavor_extra_spec",
                "/v2.1/flavors/{flavor_id}/os-extra_specs",
                "extra_specs",
                detail=False,
            ),
            *_crud(
                "server_migration",
                "/v2.1/servers/{server_id}/migrations",
                "migrations",
                detail=False,
            ),
            *_crud("console", "/v2.1/servers/{server_id}/consoles", "consoles", detail=False),
            _get(
                "/v2.1/os-console-auth-tokens/{id}", "console_auth_token_show", "console_auth_token"
            ),
            _get("/v2.1/servers/{server_id}/topology", "server_topology", "server"),
            _get("/v2.1/servers/{server_id}/os-server-password", "server_password_show", "server"),
            _delete_op(
                "/v2.1/servers/{server_id}/os-server-password", "server_password_clear", "server"
            ),
            _get("/v2.1/os-server-groups/{id}", "server_group_show", "server_group"),
        ]
    )
    return ops


def neutron_ops() -> list[dict[str, Any]]:
    ops: list[dict[str, Any]] = [
        _get("/v2.0", "neutron_versions", "version", requires_project=False)
    ]
    for res, path, key in [
        ("network", "/v2.0/networks", "networks"),
        ("subnet", "/v2.0/subnets", "subnets"),
        ("port", "/v2.0/ports", "ports"),
        ("router", "/v2.0/routers", "routers"),
        ("floatingip", "/v2.0/floatingips", "floatingips"),
        ("security_group", "/v2.0/security-groups", "security_groups"),
        ("security_group_rule", "/v2.0/security-group-rules", "security_group_rules"),
        ("address_scope", "/v2.0/address-scopes", "address_scopes"),
        ("address_group", "/v2.0/address-groups", "address_groups"),
        ("subnetpool", "/v2.0/subnetpools", "subnetpools"),
        ("qos_policy", "/v2.0/qos/policies", "policies"),
        ("trunk", "/v2.0/trunks", "trunks"),
        ("rbac_policy", "/v2.0/rbac-policies", "rbac_policies"),
        ("metering_label", "/v2.0/metering/metering-labels", "metering_labels"),
        ("metering_label_rule", "/v2.0/metering/metering-label-rules", "metering_label_rules"),
        ("firewall_group", "/v2.0/fwaas/firewall_groups", "firewall_groups"),
        ("firewall_policy", "/v2.0/fwaas/firewall_policies", "firewall_policies"),
        ("firewall_rule", "/v2.0/fwaas/firewall_rules", "firewall_rules"),
        ("vpn_service", "/v2.0/vpn/vpnservices", "vpnservices"),
        ("ipsec_site_connection", "/v2.0/vpn/ipsec-site-connections", "ipsec_site_connections"),
        ("ike_policy", "/v2.0/vpn/ikepolicies", "ikepolicies"),
        ("ipsec_policy", "/v2.0/vpn/ipsecpolicies", "ipsecpolicies"),
        ("vpn_endpoint_group", "/v2.0/vpn/endpoint-groups", "endpoint_groups"),
        ("bgpvpn", "/v2.0/bgpvpn/bgpvpns", "bgpvpns"),
        ("bgp_speaker", "/v2.0/bgp-speakers", "bgp_speakers"),
        ("bgp_peer", "/v2.0/bgp-peers", "bgp_peers"),
        ("log", "/v2.0/log/logs", "logs"),
        ("ndp_proxy", "/v2.0/ndp_proxies", "ndp_proxies"),
        ("local_ip", "/v2.0/local_ips", "local_ips"),
        ("segment", "/v2.0/segments", "segments"),
        ("network_segment_range", "/v2.0/network_segment_ranges", "network_segment_ranges"),
        ("service_profile", "/v2.0/service_profiles", "service_profiles"),
        ("neutron_flavor", "/v2.0/flavors", "flavors"),
        (
            "default_security_group_rule",
            "/v2.0/default-security-group-rules",
            "default_security_group_rules",
        ),
        ("lbaas_loadbalancer", "/v2.0/lbaas/loadbalancers", "loadbalancers"),
        ("lbaas_listener", "/v2.0/lbaas/listeners", "listeners"),
        ("lbaas_pool", "/v2.0/lbaas/pools", "pools"),
    ]:
        ops.extend(_crud(res, path, key, detail=False))
    ops.extend(
        [
            _get("/v2.0/agents", "neutron_agents", "agent", "agents"),
            _get("/v2.0/agents/{id}", "neutron_agent_show", "agent"),
            _get("/v2.0/qos/rule-types", "qos_rule_types", "qos_rule_type", "rule_types"),
            _get(
                "/v2.0/network-ip-availabilities",
                "network_ip_availabilities",
                "network_ip_availability",
                "network_ip_availabilities",
            ),
            _get(
                "/v2.0/auto-allocated-topology",
                "auto_allocated_topology",
                "auto_allocated_topology",
                "auto_allocated_topology",
            ),
            _get("/v2.0/quotas", "neutron_quota_list", "quota", "quotas"),
            _get("/v2.0/quotas/{id}", "neutron_quota_show", "quota"),
            _put("/v2.0/quotas/{id}", "neutron_quota_update", "quota"),
            _delete_op("/v2.0/quotas/{id}", "neutron_quota_delete", "quota"),
            _put("/v2.0/routers/{id}/add_router_interface", "router_add_interface", "router"),
            _put("/v2.0/routers/{id}/remove_router_interface", "router_remove_interface", "router"),
            _put("/v2.0/routers/{id}/add_extraroutes", "router_add_extraroutes", "router"),
            _put("/v2.0/routers/{id}/remove_extraroutes", "router_remove_extraroutes", "router"),
            *_crud(
                "conntrack_helper",
                "/v2.0/routers/{router_id}/conntrack_helpers",
                "conntrack_helpers",
                detail=False,
            ),
            *_crud(
                "qos_bandwidth_limit_rule",
                "/v2.0/qos/policies/{policy_id}/bandwidth_limit_rules",
                "bandwidth_limit_rules",
                detail=False,
            ),
            *_crud(
                "qos_dscp_marking_rule",
                "/v2.0/qos/policies/{policy_id}/dscp_marking_rules",
                "dscp_marking_rules",
                detail=False,
            ),
            *_crud(
                "qos_minimum_bandwidth_rule",
                "/v2.0/qos/policies/{policy_id}/minimum_bandwidth_rules",
                "minimum_bandwidth_rules",
                detail=False,
            ),
            *_crud(
                "trunk_subport", "/v2.0/trunks/{trunk_id}/add_subports", "sub_ports", detail=False
            ),
            *_crud(
                "floatingip_port_forwarding",
                "/v2.0/floatingips/{floatingip_id}/port_forwardings",
                "port_forwardings",
                detail=False,
            ),
            *_crud(
                "local_ip_association",
                "/v2.0/local_ips/{local_ip_id}/port_associations",
                "port_associations",
                detail=False,
            ),
            *_crud(
                "bgpvpn_network_association",
                "/v2.0/bgpvpn/bgpvpns/{bgpvpn_id}/network_associations",
                "network_associations",
                detail=False,
            ),
            *_crud(
                "bgpvpn_router_association",
                "/v2.0/bgpvpn/bgpvpns/{bgpvpn_id}/router_associations",
                "router_associations",
                detail=False,
            ),
        ]
    )
    return ops


def glance_ops() -> list[dict[str, Any]]:
    ops = [_get("/v2", "glance_versions", "version", requires_project=False)]
    ops.extend(_crud("image", "/v2/images", "images", detail=False))
    ops.extend(
        [
            _put("/v2/images/{id}/file", "image_upload", "image"),
            _get("/v2/images/{id}/file", "image_download", "image"),
            *_crud("metadef_namespace", "/v2/metadefs/namespaces", "namespaces", detail=False),
            *_crud("task", "/v2/tasks", "tasks", detail=False),
            _get("/v2/info/import", "glance_import_info", "info_import", "import-methods"),
            _get("/v2/info/stores", "glance_stores", "info_store", "stores"),
            _get("/v2/schemas/image", "glance_schema_image", "schema"),
            _get("/v2/schemas/images", "glance_schema_images", "schema"),
            _post("/v2/images/{id}/actions/deactivate", "image_deactivate", "image", status=204),
            _post("/v2/images/{id}/actions/reactivate", "image_reactivate", "image", status=204),
            *_crud("image_member", "/v2/images/{image_id}/members", "members", detail=False),
            *_crud("image_tag", "/v2/images/{image_id}/tags", "tags", detail=False),
        ]
    )
    return ops


def cinder_ops() -> list[dict[str, Any]]:
    ops = [_get("/v3", "cinder_versions", "version", requires_project=False)]
    for res, path, key in [
        ("volume", "/v3/volumes", "volumes"),
        ("snapshot", "/v3/snapshots", "snapshots"),
        ("backup", "/v3/backups", "backups"),
        ("volume_type", "/v3/types", "volume_types"),
        ("qos_spec", "/v3/qos-specs", "qos_specs"),
        ("group", "/v3/groups", "groups"),
        ("group_snapshot", "/v3/group_snapshots", "group_snapshots"),
        ("consistencygroup", "/v3/consistencygroups", "consistencygroups"),
        ("attachment", "/v3/attachments", "attachments"),
        ("transfer", "/v3/volume-transfers", "transfers"),
        ("message", "/v3/messages", "messages"),
        ("cluster", "/v3/clusters", "clusters"),
    ]:
        ops.extend(_crud(res, path, key))
    # project-scoped aliases
    ops.extend(_crud("volume_tenant", "/v3/{project_id}/volumes", "volumes"))
    ops.extend(
        [
            {
                "operation_id": "volume_action",
                "method": "POST",
                "path": "/v3/volumes/{id}/action",
                "resource_type": "volume",
                "kind": "action",
                "status_code": 202,
                "action_name": "*",
            },
            _get("/v3/os-services", "cinder_services", "service", "services"),
            _get("/v3/limits", "cinder_limits", "limit", "limits"),
            _get("/v3/os-quota-sets/{id}", "cinder_quota_show", "quota_set", "quota_set"),
            _get(
                "/v3/resource_filters",
                "cinder_resource_filters",
                "resource_filter",
                "resource_filters",
            ),
            _get("/v3/scheduler-stats/get_pools", "cinder_pools", "pool", "pools"),
        ]
    )
    return ops


def placement_ops() -> list[dict[str, Any]]:
    ops = [
        _get("/", "placement_root", "version", requires_project=False),
    ]
    for res, path, key in [
        ("resource_provider", "/resource_providers", "resource_providers"),
        ("resource_class", "/resource_classes", "resource_classes"),
        ("trait", "/traits", "traits"),
    ]:
        ops.extend(_crud(res, path, key, detail=False))
    ops.extend(
        [
            _get("/allocations/{consumer_uuid}", "allocation_show", "allocation", "allocations"),
            _put("/allocations/{consumer_uuid}", "allocation_set", "allocation"),
            _delete_op("/allocations/{consumer_uuid}", "allocation_delete", "allocation"),
            _get(
                "/allocation_candidates",
                "allocation_candidates",
                "allocation_candidate",
                "allocation_requests",
            ),
            _get("/usages", "usages", "usage", "usages"),
            _get(
                "/resource_providers/{id}/inventories", "rp_inventories", "inventory", "inventories"
            ),
            _put("/resource_providers/{id}/inventories", "rp_inventories_set", "inventory"),
            _get("/resource_providers/{id}/aggregates", "rp_aggregates", "aggregate", "aggregates"),
            _get("/resource_providers/{id}/traits", "rp_traits", "trait", "traits"),
            _get("/resource_providers/{id}/usages", "rp_usages", "usage", "usages"),
            _get(
                "/resource_providers/{id}/allocations",
                "rp_allocations",
                "allocation",
                "allocations",
            ),
        ]
    )
    return ops


def heat_ops() -> list[dict[str, Any]]:
    ops = [_get("/v1", "heat_versions", "version", requires_project=False)]
    base = "/v1/{tenant_id}"
    ops.extend(_crud("stack", f"{base}/stacks", "stacks", detail=False))
    ops.extend(
        [
            _get(f"{base}/stacks/detail", "stack_list_detail", "stack", "stacks"),
            _get(
                f"{base}/stacks/{{stack_name}}/{{stack_id}}", "stack_show_by_name", "stack", "stack"
            ),
            _delete_op(
                f"{base}/stacks/{{stack_name}}/{{stack_id}}", "stack_delete_by_name", "stack"
            ),
            *_crud(
                "stack_resource",
                f"{base}/stacks/{{stack_name}}/{{stack_id}}/resources",
                "resources",
                detail=False,
            ),
            *_crud(
                "stack_event",
                f"{base}/stacks/{{stack_name}}/{{stack_id}}/events",
                "events",
                detail=False,
            ),
            *_crud("software_config", f"{base}/software_configs", "software_configs", detail=False),
            *_crud(
                "software_deployment",
                f"{base}/software_deployments",
                "software_deployments",
                detail=False,
            ),
            _get(
                f"{base}/resource_types", "heat_resource_types", "resource_type", "resource_types"
            ),
            _get(f"{base}/services", "heat_services", "service", "services"),
            _post(f"{base}/stacks/preview", "stack_preview", "stack", "stack", status=200),
            _post(f"{base}/validate", "template_validate", "template", status=200),
        ]
    )
    return ops


def heat_cfn_ops() -> list[dict[str, Any]]:
    return [
        *_crud("stack", "/stacks", "Stacks", detail=False),
        _get("/v1", "heat_cfn_versions", "version", requires_project=False),
        _post("/", "heat_cfn_query", "stack", status=200, requires_project=False),
    ]


def swift_ops() -> list[dict[str, Any]]:
    return [
        _get("/info", "swift_info", "info", requires_auth=False, requires_project=False),
        _get("/v1/{account}", "swift_account_get", "account", requires_project=False),
        _post("/v1/{account}", "swift_account_post", "account", status=204),
        _get("/v1/{account}/{container}", "swift_container_get", "container"),
        _put("/v1/{account}/{container}", "swift_container_put", "container"),
        _delete_op("/v1/{account}/{container}", "swift_container_delete", "container"),
        _get("/v1/{account}/{container}/{object}", "swift_object_get", "object"),
        _put("/v1/{account}/{container}/{object}", "swift_object_put", "object"),
        _delete_op("/v1/{account}/{container}/{object}", "swift_object_delete", "object"),
        _post("/v1/{account}/{container}/{object}", "swift_object_post", "object", status=202),
    ]


def ironic_ops() -> list[dict[str, Any]]:
    ops = [_get("/v1", "ironic_versions", "version", requires_project=False)]
    for res, path, key in [
        ("node", "/v1/nodes", "nodes"),
        ("port", "/v1/ports", "ports"),
        ("portgroup", "/v1/portgroups", "portgroups"),
        ("chassis", "/v1/chassis", "chassis"),
        ("allocation", "/v1/allocations", "allocations"),
        ("deploy_template", "/v1/deploy_templates", "deploy_templates"),
        ("volume_connector", "/v1/volume/connectors", "connectors"),
        ("volume_target", "/v1/volume/targets", "targets"),
    ]:
        ops.extend(_crud(res, path, key, detail=False))
    ops.extend(
        [
            _get("/v1/drivers", "ironic_drivers", "driver", "drivers"),
            _get("/v1/drivers/{name}", "ironic_driver_show", "driver"),
            _get("/v1/conductors", "ironic_conductors", "conductor", "conductors"),
            _put("/v1/nodes/{id}/states/provision", "node_provision_state", "node"),
            _put("/v1/nodes/{id}/states/power", "node_power_state", "node"),
            _put("/v1/nodes/{id}/states/raid", "node_raid_state", "node"),
            _get("/v1/nodes/{id}/states", "node_states", "node"),
            _get("/v1/nodes/{id}/vendor_passthru", "node_vendor_passthru", "node"),
            {
                "operation_id": "node_action",
                "method": "POST",
                "path": "/v1/nodes/{id}/vifs",
                "resource_type": "node",
                "kind": "action",
                "status_code": 204,
            },
        ]
    )
    return ops


def octavia_ops() -> list[dict[str, Any]]:
    ops = [_get("/v2", "octavia_versions", "version", requires_project=False)]
    for res, path, key in [
        ("loadbalancer", "/v2/lbaas/loadbalancers", "loadbalancers"),
        ("listener", "/v2/lbaas/listeners", "listeners"),
        ("pool", "/v2/lbaas/pools", "pools"),
        ("healthmonitor", "/v2/lbaas/healthmonitors", "healthmonitors"),
        ("l7policy", "/v2/lbaas/l7policies", "l7policies"),
        ("flavor", "/v2/lbaas/flavors", "flavors"),
        ("flavorprofile", "/v2/lbaas/flavorprofiles", "flavorprofiles"),
        ("amphora", "/v2/octavia/amphorae", "amphorae"),
        ("quota", "/v2/lbaas/quotas", "quotas"),
        ("provider", "/v2/lbaas/providers", "providers"),
    ]:
        ops.extend(_crud(res, path, key, detail=False))
    ops.extend(_crud("member", "/v2/lbaas/pools/{pool_id}/members", "members", detail=False))
    ops.extend(_crud("l7rule", "/v2/lbaas/l7policies/{l7policy_id}/rules", "rules", detail=False))
    ops.append(
        {
            "operation_id": "loadbalancer_failover",
            "method": "PUT",
            "path": "/v2/lbaas/loadbalancers/{id}/failover",
            "resource_type": "loadbalancer",
            "kind": "action",
            "status_code": 202,
        }
    )
    return ops


def _simple_service_ops(
    resources: list[tuple[str, str, str]],
    *,
    version_get: tuple[str, str] | None = None,
    extras: list[dict[str, Any]] | None = None,
) -> list[dict[str, Any]]:
    ops: list[dict[str, Any]] = []
    if version_get:
        ops.append(_get(version_get[0], version_get[1], "version", requires_project=False))
    for res, path, key in resources:
        ops.extend(_crud(res, path, key, detail=False))
    ops.extend(extras or [])
    return ops


def build_all_operations() -> dict[str, list[dict[str, Any]]]:
    return {
        "keystone": keystone_ops(),
        "nova": nova_ops(),
        "neutron": neutron_ops(),
        "glance": glance_ops(),
        "cinder": cinder_ops(),
        "placement": placement_ops(),
        "heat": heat_ops(),
        "heat-cfn": heat_cfn_ops(),
        "swift": swift_ops(),
        "ironic": ironic_ops(),
        "octavia": octavia_ops(),
        "barbican": _simple_service_ops(
            [
                ("secret", "/v1/secrets", "secrets"),
                ("container", "/v1/containers", "containers"),
                ("order", "/v1/orders", "orders"),
                ("secret_store", "/v1/secret-stores", "secret_stores"),
            ],
            version_get=("/v1", "barbican_versions"),
        ),
        "manila": _simple_service_ops(
            [
                ("share", "/v2/shares", "shares"),
                ("share_snapshot", "/v2/snapshots", "snapshots"),
                ("share_network", "/v2/share-networks", "share_networks"),
                ("share_type", "/v2/types", "share_types"),
                ("share_server", "/v2/share-servers", "share_servers"),
                ("security_service", "/v2/security-services", "security_services"),
                ("share_group", "/v2/share-groups", "share_groups"),
                ("share_replica", "/v2/share-replicas", "share_replicas"),
            ],
            version_get=("/v2", "manila_versions"),
            extras=[
                {
                    "operation_id": "share_action",
                    "method": "POST",
                    "path": "/v2/shares/{id}/action",
                    "resource_type": "share",
                    "kind": "action",
                    "status_code": 202,
                    "action_name": "*",
                }
            ],
        ),
        "designate": _simple_service_ops(
            [
                ("zone", "/v2/zones", "zones"),
                ("recordset", "/v2/zones/{zone_id}/recordsets", "recordsets"),
                ("tld", "/v2/tlds", "tlds"),
                ("blacklist", "/v2/blacklists", "blacklists"),
                ("pool", "/v2/pools", "pools"),
                ("service_status", "/v2/service_statuses", "service_statuses"),
            ],
            version_get=("/v2", "designate_versions"),
        ),
        "magnum": _simple_service_ops(
            [
                ("cluster", "/v1/clusters", "clusters"),
                ("clustertemplate", "/v1/clustertemplates", "clustertemplates"),
                ("certificate", "/v1/certificates", "certificates"),
                ("nodegroup", "/v1/clusters/{cluster_id}/nodegroups", "nodegroups"),
            ],
            version_get=("/v1", "magnum_versions"),
        ),
        "zun": _simple_service_ops(
            [
                ("container", "/v1/containers", "containers"),
                ("image", "/v1/images", "images"),
                ("capsule", "/v1/capsules", "capsules"),
                ("host", "/v1/hosts", "hosts"),
                ("service", "/v1/services", "services"),
            ],
            version_get=("/v1", "zun_versions"),
            extras=[
                {
                    "operation_id": "container_action",
                    "method": "POST",
                    "path": "/v1/containers/{id}/start",
                    "resource_type": "container",
                    "kind": "action",
                    "status_code": 202,
                },
                {
                    "operation_id": "container_stop",
                    "method": "POST",
                    "path": "/v1/containers/{id}/stop",
                    "resource_type": "container",
                    "kind": "action",
                    "status_code": 202,
                },
            ],
        ),
        "trove": _simple_service_ops(
            [
                ("instance", "/v1.0/instances", "instances"),
                ("datastore", "/v1.0/datastores", "datastores"),
                ("backup", "/v1.0/backups", "backups"),
                ("configuration", "/v1.0/configurations", "configurations"),
                ("cluster", "/v1.0/clusters", "clusters"),
            ],
            version_get=("/v1.0", "trove_versions"),
        ),
        "mistral": _simple_service_ops(
            [
                ("workflow", "/v2/workflows", "workflows"),
                ("execution", "/v2/executions", "executions"),
                ("action", "/v2/actions", "actions"),
                ("workbook", "/v2/workbooks", "workbooks"),
                ("cron_trigger", "/v2/cron_triggers", "cron_triggers"),
                ("task", "/v2/tasks", "tasks"),
            ],
            version_get=("/v2", "mistral_versions"),
        ),
        "aodh": _simple_service_ops(
            [
                ("alarm", "/v2/alarms", "alarms"),
                ("alarm_history", "/v2/alarms/{alarm_id}/history", "alarm_history"),
                ("quota", "/v2/quotas", "quotas"),
            ],
            version_get=("/v2", "aodh_versions"),
        ),
        "cloudkitty": _simple_service_ops(
            [
                ("hashmap_service", "/v1/rating/module_config/hashmap/services", "services"),
                ("hashmap_field", "/v1/rating/module_config/hashmap/fields", "fields"),
                ("report_summary", "/v1/report/summary", "summary"),
                ("dataframes", "/v1/storage/dataframes", "dataframes"),
            ],
            version_get=("/v1", "cloudkitty_versions"),
        ),
        "freezer": _simple_service_ops(
            [
                ("job", "/v2/jobs", "jobs"),
                ("client", "/v2/clients", "clients"),
                ("backup", "/v2/backups", "backups"),
                ("session", "/v2/sessions", "sessions"),
                ("action", "/v2/actions", "actions"),
            ],
            version_get=("/v2", "freezer_versions"),
        ),
        "blazar": _simple_service_ops(
            [
                ("lease", "/leases", "leases"),
                ("host", "/os-hosts", "hosts"),
                ("floatingip", "/floatingips", "floatingips"),
            ],
            version_get=("/v1", "blazar_versions"),
        ),
        "vitrage": _simple_service_ops(
            [
                ("topology", "/v1/topology", "topology"),
                ("alarm", "/v1/alarm", "alarms"),
                ("resource", "/v1/resources", "resources"),
                ("template", "/v1/template", "templates"),
                ("event", "/v1/event", "events"),
            ],
        ),
        "masakari": _simple_service_ops(
            [
                ("segment", "/v1/segments", "segments"),
                ("host", "/v1/segments/{segment_id}/hosts", "hosts"),
                ("notification", "/v1/notifications", "notifications"),
            ],
            version_get=("/v1", "masakari_versions"),
        ),
        "tacker": _simple_service_ops(
            [
                ("vnf", "/v1.0/vnfs", "vnfs"),
                ("vnfd", "/v1.0/vnfds", "vnfds"),
                ("vim", "/v1.0/vims", "vims"),
                ("vnf_package", "/vnfpkgm/v1/vnf_packages", "vnf_packages"),
                ("vnf_instance", "/vnflcm/v1/vnf_instances", "vnf_instances"),
            ],
        ),
        "adjutant": _simple_service_ops(
            [
                ("task", "/v1/tasks", "tasks"),
                ("token", "/v1/tokens", "tokens"),
                ("notification", "/v1/notifications", "notifications"),
                ("status", "/v1/status", "status"),
            ],
        ),
        # https://docs.openstack.org/2024.2/api/ — Infrastructure Optimization + Messaging
        "watcher": _simple_service_ops(
            [
                ("audit_template", "/v1/audit_templates", "audit_templates"),
                ("audit", "/v1/audits", "audits"),
                ("action_plan", "/v1/action_plans", "action_plans"),
                ("action", "/v1/actions", "actions"),
                ("goal", "/v1/goals", "goals"),
                ("strategy", "/v1/strategies", "strategies"),
                ("scoring_engine", "/v1/scoring_engines", "scoring_engines"),
                ("service", "/v1/services", "services"),
            ],
            version_get=("/v1", "watcher_versions"),
        ),
        "zaqar": _simple_service_ops(
            [
                ("queue", "/v2/queues", "queues"),
                ("subscription", "/v2/queues/{queue_name}/subscriptions", "subscriptions"),
                ("claim", "/v2/queues/{queue_name}/claims", "claims"),
                ("message", "/v2/queues/{queue_name}/messages", "messages"),
            ],
            version_get=("/v2", "zaqar_versions"),
            extras=[
                _get("/v2/health", "zaqar_health", "health", requires_project=False),
                _get("/v2/ping", "zaqar_ping", "ping", requires_auth=False, requires_project=False),
            ],
        ),
    }
