"""Exportação read-only da matriz Spec 027 para UI preview."""

from __future__ import annotations

import os
from typing import Any

from app.platform_role_catalog import catalog_export
from app.agents.catalog import AGENT_CATALOG
from app import agent_bindings

# Legenda global Spec 027
LEGEND = {
    "full": {"symbol": "✅", "label": "Acesso total", "access": "full"},
    "read": {"symbol": "🔒", "label": "Só leitura", "access": "read"},
    "link": {"symbol": "🔗", "label": "Deep-link", "access": "link"},
    "api": {"symbol": "⚙️", "label": "Via API Desk", "access": "api"},
    "system": {"symbol": "🤖", "label": "Conta sistema", "access": "system"},
    "none": {"symbol": "❌", "label": "Sem acesso", "access": "none"},
}

ROLE_COLUMNS = [
    "super_admin", "ops_lead", "technician", "noc", "finance",
    "sales_admin", "sales_support", "marketing", "seo", "developer",
    "devops", "security_analyst", "content_editor", "agentic_operator",
]

# Spec 027 §3.1 — módulos Desk × função
DESK_MODULE_MATRIX: dict[str, dict[str, str]] = {
    "core": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
        "finance": "read", "sales_admin": "full", "sales_support": "full",
        "marketing": "read", "seo": "read", "developer": "read", "devops": "read",
        "security_analyst": "read", "content_editor": "read", "agentic_operator": "read",
    },
    "overview": {
        "super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "read",
        "finance": "read", "sales_admin": "full", "sales_support": "read",
        "marketing": "read", "seo": "read", "developer": "read", "devops": "read",
        "security_analyst": "read", "content_editor": "none", "agentic_operator": "read",
    },
    "overview-home": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
        "finance": "read", "sales_admin": "full", "sales_support": "full",
        "marketing": "read", "seo": "read", "developer": "read", "devops": "full",
        "security_analyst": "read", "content_editor": "read", "agentic_operator": "read",
    },
    "infra": {
        "super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "read",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "read", "developer": "read", "devops": "none",
        "security_analyst": "full", "content_editor": "none", "agentic_operator": "read",
    },
    "infra2-soc": {
        "super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "read",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "none",
        "security_analyst": "full", "content_editor": "none", "agentic_operator": "read",
    },
    "funnel-timing": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
        "finance": "read", "sales_admin": "full", "sales_support": "full",
        "marketing": "full", "seo": "full", "developer": "read", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "read",
    },
    "wazuh-soc": {
        "super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "read",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "read",
        "security_analyst": "full", "content_editor": "none", "agentic_operator": "read",
    },
    "leads": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "none",
        "finance": "read", "sales_admin": "full", "sales_support": "full",
        "marketing": "full", "seo": "full", "developer": "none", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
    "events": {
        "super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "read",
        "finance": "read", "sales_admin": "read", "sales_support": "read",
        "marketing": "read", "seo": "read", "developer": "api", "devops": "api",
        "security_analyst": "read", "content_editor": "none", "agentic_operator": "api",
    },
    "tenants": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
        "finance": "read", "sales_admin": "full", "sales_support": "read",
        "marketing": "read", "seo": "read", "developer": "read", "devops": "read",
        "security_analyst": "read", "content_editor": "none", "agentic_operator": "read",
    },
    "messages": {
        "super_admin": "full", "ops_lead": "none", "technician": "none", "noc": "none",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
    "admin-users": {
        "super_admin": "full", "ops_lead": "none", "technician": "none", "noc": "none",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
    "billing-recurrence": {
        "super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "none",
        "finance": "full", "sales_admin": "full", "sales_support": "read",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
    "migration": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "read",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
    "assist": {
        "super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
    "modules": {
        "super_admin": "full", "ops_lead": "none", "technician": "none", "noc": "none",
        "finance": "none", "sales_admin": "none", "sales_support": "none",
        "marketing": "none", "seo": "none", "developer": "none", "devops": "none",
        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none",
    },
}

DESK_MODULE_LABELS: dict[str, str] = {
    "core": "Núcleo (dashboard/tickets)",
    "overview": "Audit Overview",
    "overview-home": "Serviços IaaS",
    "infra": "INFRA CODE",
    "infra2-soc": "Infra 2 SOC",
    "funnel-timing": "Relógio por fase",
    "wazuh-soc": "Wazuh SOC",
    "leads": "Leads / abandono CRM",
    "events": "Eventos / webhooks",
    "tenants": "Tenants",
    "messages": "Mensagens (cadastro)",
    "admin-users": "Administradores",
    "billing-recurrence": "Billing recorrente",
    "migration": "Migração e-mail",
    "assist": "Assist / takeover",
    "modules": "Toggle módulos",
}

AGENTS_LEGACY = [
    {"id": "A0", "name": "Maestro", "role": "Orquestrador multi-agente", "approval": "agentic_operator / ops_lead"},
    {"id": "A1", "name": "Node Health", "role": "CPU, RAM, serviços Carbonio", "approval": "ops_lead (restart)"},
    {"id": "A2", "name": "Infra Mail", "role": "DNS, LE, Traefik, nginx", "approval": "devops / ops_lead"},
    {"id": "A3", "name": "Deliverability", "role": "SPF/DKIM/DMARC", "approval": "seo / technician"},
    {"id": "A4", "name": "Security Mail", "role": "amavis, spam, clamav", "approval": "security_analyst"},
    {"id": "A5", "name": "Wazuh SOC", "role": "Correlação SIEM", "approval": "security_analyst / noc"},
    {"id": "A6", "name": "Support Copilot", "role": "Assistência tickets", "approval": "technician"},
    {"id": "A7", "name": "Remediation", "role": "Runbooks", "approval": "agentic_operator (obrigatório)"},
]

# Spec 027 §6 — governança Agentics (fonte: catalog.py + permissions + agents/routes.py)
AGENTIC_GOVERNANCE: dict[str, Any] = {
    "use_ui": [
        "super_admin", "ops_lead", "technician", "noc",
        "agentic_operator", "developer", "devops", "security_analyst",
    ],
    "trigger_runs": ["super_admin", "ops_lead", "agentic_operator"],
    "approve_runbooks": ["super_admin", "ops_lead", "agentic_operator", "security_analyst"],
    "configure_models": ["super_admin", "developer"],
    "labels": {
        "use_ui": "Usa módulo Agentics (chat, findings, inbox)",
        "trigger_runs": "Dispara cenários manualmente",
        "approve_runbooks": "Aprova runbooks A7 / remediação",
        "configure_models": "Configura modelos/prompts LLM",
    },
}

# Por agente: quem aprova acções sensíveis vs quem opera no dia-a-dia
AGENT_ROLE_MAP: dict[str, dict[str, list[str]]] = {
    "A0": {
        "approvers": ["agentic_operator", "ops_lead"],
        "operators": ["super_admin", "ops_lead", "agentic_operator"],
    },
    "A1": {
        "approvers": ["ops_lead"],
        "operators": ["ops_lead", "devops", "noc", "super_admin", "agentic_operator"],
    },
    "A2": {
        "approvers": ["devops", "ops_lead"],
        "operators": ["devops", "ops_lead", "developer", "super_admin"],
    },
    "A3": {
        "approvers": ["seo", "technician"],
        "operators": ["seo", "technician", "ops_lead", "super_admin"],
    },
    "A4": {
        "approvers": ["security_analyst"],
        "operators": ["security_analyst", "ops_lead", "super_admin"],
    },
    "A5": {
        "approvers": ["security_analyst", "noc"],
        "operators": ["security_analyst", "noc", "ops_lead", "agentic_operator", "super_admin"],
    },
    "A6": {
        "approvers": ["technician"],
        "operators": ["technician", "ops_lead", "agentic_operator", "super_admin"],
    },
    "A7": {
        "approvers": ["agentic_operator", "ops_lead", "super_admin"],
        "operators": ["agentic_operator", "ops_lead", "super_admin"],
    },
}

AGENT_RELATION_LABELS = {
    "approve": "Aprova acções sensíveis",
    "focus": "Operador principal",
    "ui": "Acede UI Agentics",
}

CATEGORY_LABELS = {
    "ops": "Operações",
    "commercial": "Comercial",
    "business": "Negócio",
    "platform": "Plataforma",
    "system": "Sistema",
}

# Spec 027 §2 / §4 / §5 — software em escopo (fora do Desk, dentro da plataforma Ligbox)
SOFTWARE_GROUPS: list[dict[str, Any]] = [
    {
        "id": "vm112",
        "label": "VM112 — Onboard & Mail",
        "host": "10.10.10.112",
        "url": "https://onboard.ligbox.com.br",
        "items": [
            {"id": "wizard_assist", "label": "Wizard assist / takeover", "product": "ligbox-wizard",
             "levels": {"super_admin": "full", "ops_lead": "full", "technician": "full", "noc": "read",
                        "finance": "read", "marketing": "read", "seo": "read", "developer": "api",
                        "sales_admin": "read", "sales_support": "read", "devops": "read",
                        "security_analyst": "read", "content_editor": "none", "agentic_operator": "read"}},
            {"id": "vm112_api", "label": "API VM112 (:8090)", "product": "ligbox-wizard",
             "levels": {"super_admin": "full", "ops_lead": "full", "technician": "api", "noc": "read",
                        "finance": "read", "marketing": "read", "seo": "read", "developer": "full",
                        "sales_admin": "read", "sales_support": "read", "devops": "full",
                        "security_analyst": "read", "content_editor": "none", "agentic_operator": "api"}},
            {"id": "carbonio_admin", "label": "Carbonio admin (mail tenant)", "product": "Carbonio",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "link", "noc": "none",
                        "finance": "none", "marketing": "none", "seo": "none", "developer": "none",
                        "sales_admin": "none", "sales_support": "none", "devops": "link",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "vm112_ssh", "label": "SSH VM112", "product": "Linux",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "none", "marketing": "none", "seo": "none", "developer": "link",
                        "sales_admin": "none", "sales_support": "none", "devops": "full",
                        "security_analyst": "link", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "purge_domain", "label": "Purge domínio", "product": "ligbox-wizard",
             "levels": {"super_admin": "full", "ops_lead": "full", "technician": "none", "noc": "none",
                        "finance": "none", "marketing": "none", "seo": "none", "developer": "none",
                        "sales_admin": "none", "sales_support": "none", "devops": "api",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
        ],
    },
    {
        "id": "vm123",
        "label": "VM123 — Finance & Hosting",
        "host": "10.10.10.123",
        "url": "https://financeiro.ligbox.com.br",
        "items": [
            {"id": "foss_admin", "label": "FOSSBilling Admin", "product": "FOSSBilling",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "full", "sales_admin": "full", "sales_support": "full",
                        "marketing": "read", "seo": "none", "developer": "api", "devops": "none",
                        "security_analyst": "read", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "foss_client", "label": "FOSSBilling Cliente", "product": "FOSSBilling",
             "levels": {"super_admin": "full", "ops_lead": "read", "technician": "none", "noc": "none",
                        "finance": "full", "sales_admin": "full", "sales_support": "full",
                        "marketing": "full", "seo": "none", "developer": "none", "devops": "none",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "odoo16", "label": "Odoo 16 (CRM / Invoicing)", "product": "Odoo",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "full", "sales_admin": "full", "sales_support": "full",
                        "marketing": "none", "seo": "none", "developer": "api", "devops": "none",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "openpanel", "label": "OpenPanel (hosting sites)", "product": "OpenPanel",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "link", "noc": "none",
                        "finance": "read", "sales_admin": "link", "sales_support": "link",
                        "marketing": "full", "seo": "full", "developer": "api", "devops": "full",
                        "security_analyst": "read", "content_editor": "full", "agentic_operator": "none"}},
            {"id": "openadmin", "label": "OpenAdmin", "product": "OpenPanel",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "read", "sales_admin": "link", "sales_support": "none",
                        "marketing": "link", "seo": "link", "developer": "none", "devops": "full",
                        "security_analyst": "read", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "vm123_ssh", "label": "SSH VM123 (:2523)", "product": "Linux",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "link", "sales_admin": "none", "sales_support": "none",
                        "marketing": "none", "seo": "none", "developer": "link", "devops": "full",
                        "security_analyst": "link", "content_editor": "none", "agentic_operator": "none"}},
        ],
    },
    {
        "id": "externas",
        "label": "Consolas & Infra (deep-link / API)",
        "host": "—",
        "url": "",
        "items": [
            {"id": "cloudflare", "label": "Cloudflare DNS", "product": "Cloudflare",
             "levels": {"super_admin": "full", "ops_lead": "full", "technician": "link", "noc": "none",
                        "finance": "none", "sales_admin": "read", "sales_support": "read",
                        "marketing": "read", "seo": "full", "developer": "none", "devops": "full",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "traefik", "label": "Traefik CT114", "product": "Traefik",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "none", "sales_admin": "none", "sales_support": "none",
                        "marketing": "none", "seo": "none", "developer": "link", "devops": "full",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "proxmox", "label": "Proxmox host", "product": "Proxmox",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "none", "sales_admin": "none", "sales_support": "none",
                        "marketing": "none", "seo": "none", "developer": "none", "devops": "full",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "pfsense", "label": "pfSense API", "product": "pfSense",
             "levels": {"super_admin": "full", "ops_lead": "link", "technician": "none", "noc": "none",
                        "finance": "none", "sales_admin": "none", "sales_support": "none",
                        "marketing": "none", "seo": "none", "developer": "none", "devops": "full",
                        "security_analyst": "link", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "wazuh", "label": "Wazuh VM104", "product": "Wazuh",
             "levels": {"super_admin": "full", "ops_lead": "full", "technician": "read", "noc": "read",
                        "finance": "none", "sales_admin": "none", "sales_support": "none",
                        "marketing": "none", "seo": "none", "developer": "none", "devops": "read",
                        "security_analyst": "full", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "github", "label": "GitHub itecnologys/*", "product": "GitHub",
             "levels": {"super_admin": "full", "ops_lead": "read", "technician": "none", "noc": "none",
                        "finance": "none", "sales_admin": "none", "sales_support": "none",
                        "marketing": "none", "seo": "none", "developer": "full", "devops": "none",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
            {"id": "gsc", "label": "Google Search Console", "product": "Google",
             "levels": {"super_admin": "none", "ops_lead": "none", "technician": "none", "noc": "none",
                        "finance": "none", "sales_admin": "none", "sales_support": "none",
                        "marketing": "link", "seo": "full", "developer": "none", "devops": "none",
                        "security_analyst": "none", "content_editor": "none", "agentic_operator": "none"}},
        ],
    },
]


def _software_groups_export() -> list[dict[str, Any]]:
    out = []
    for grp in SOFTWARE_GROUPS:
        items = []
        for item in grp["items"]:
            levels = item.get("levels", {})
            items.append({
                **item,
                "levels": {role: levels.get(role, "none") for role in ROLE_COLUMNS},
            })
        out.append({**grp, "items": items})
    return out


def _agent_role_relations_from_db(conn, agent_id: str, role_id: str) -> list[str]:
    return agent_bindings.agent_relations(conn, agent_id, role_id)


def _agents_export(conn) -> list[dict[str, Any]]:
    order = ["A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7"]
    matrix = agent_bindings.load_bindings_matrix(conn)
    out: list[dict[str, Any]] = []
    for aid in order:
        p = AGENT_CATALOG.get(aid)
        if not p:
            continue
        mapping = AGENT_ROLE_MAP.get(aid, {})
        role_levels = {role: _agent_role_relations_from_db(conn, aid, role) for role in ROLE_COLUMNS}
        role_bindings = matrix["agents"].get(aid, {})
        out.append({
            "id": p.id,
            "codename": p.codename,
            "name": p.name,
            "role": p.role,
            "reads": list(p.reads),
            "actions": list(p.actions),
            "approval_text": p.approval,
            "approvers": mapping.get("approvers", []),
            "operators": mapping.get("operators", []),
            "scenarios": list(p.scenarios),
            "role_relations": role_levels,
            "bindings": role_bindings,
        })
    return out


def _role_agents_summary(conn, role_id: str) -> list[dict[str, Any]]:
    rows = []
    for agent in _agents_export(conn):
        rels = agent["role_relations"].get(role_id, [])
        if not rels:
            continue
        rows.append({
            "id": agent["id"],
            "name": agent["name"],
            "role": agent["role"],
            "relations": rels,
            "relation_labels": [AGENT_RELATION_LABELS[r] for r in rels if r in AGENT_RELATION_LABELS],
            "is_approver": "approve" in rels,
            "is_operator": "focus" in rels,
        })
    return rows


def _role_agentic_caps(conn, role_id: str) -> list[dict[str, str]]:
    return agent_bindings.role_agentic_caps(conn, role_id)


def _role_software_summary(role_id: str) -> list[dict[str, Any]]:
    """Visão «cartão de função» — todos os SW onde a função tem acesso ≠ none."""
    rows = []
    for grp in SOFTWARE_GROUPS:
        for item in grp["items"]:
            lv = item.get("levels", {}).get(role_id, "none")
            if lv == "none":
                continue
            rows.append({
                "group": grp["label"],
                "product": item.get("product", ""),
                "label": item["label"],
                "level": lv,
                "host": grp.get("host", ""),
                "url": grp.get("url", ""),
            })
    return rows


def _all_role_software_summaries() -> dict[str, list[dict[str, Any]]]:
    return {role: _role_software_summary(role) for role in ROLE_COLUMNS}


def _desk_modules_export() -> list[dict[str, Any]]:
    rows = []
    for mod_id, levels in DESK_MODULE_MATRIX.items():
        rows.append({
            "id": mod_id,
            "label": DESK_MODULE_LABELS.get(mod_id, mod_id),
            "levels": {role: levels.get(role, "none") for role in ROLE_COLUMNS},
        })
    return rows


def matrix_export(conn) -> dict[str, Any]:
    catalog = catalog_export()
    bindings_matrix = agent_bindings.load_bindings_matrix(conn)
    edit_enabled = os.getenv("ACCESS_MATRIX_EDIT", "0").strip().lower() in ("1", "true", "yes", "on")
    return {
        "spec": "027",
        "preview_mode": not edit_enabled,
        "read_only": not edit_enabled,
        "editable": edit_enabled,
        "legend": LEGEND,
        "role_columns": ROLE_COLUMNS,
        "category_labels": CATEGORY_LABELS,
        "desk_modules": _desk_modules_export(),
        "software_groups": _software_groups_export(),
        "role_software_summaries": _all_role_software_summaries(),
        "role_agents_summaries": {role: _role_agents_summary(conn, role) for role in ROLE_COLUMNS},
        "role_agentic_caps": {role: _role_agentic_caps(conn, role) for role in ROLE_COLUMNS},
        "agent_bindings_matrix": bindings_matrix,
        "agentic_governance": AGENTIC_GOVERNANCE,
        "agent_relation_labels": AGENT_RELATION_LABELS,
        "agents": _agents_export(conn),
        "catalog": catalog,
        "tabs": [
            {"id": "overview", "label": "Visão da função", "type": "overview",
             "hint": "Desk + software + APIs da função seleccionada"},
            {"id": "quem-faz-o-que", "label": "Quem faz o quê", "type": "executive_map",
             "hint": "Mapa executivo Spec 039 — editar permissões por acção"},
            {"id": "vm122", "label": "Matriz Desk", "type": "desk_modules",
             "hint": "VM122 — módulos internos da plataforma"},
            {"id": "software", "label": "Software & Infra", "type": "software",
             "hint": "VM112 · VM123 · consolas externas"},
            {"id": "bindings", "label": "APIs & Grupos", "type": "catalog",
             "hint": "Bindings Odoo-style — grupos, roles, permissões"},
            {"id": "agents", "label": "Agentes IA", "type": "agents",
             "hint": "A0–A7 — orquestração e aprovações"},
            {"id": "access-control", "label": "Controle de acesso", "type": "user_admin",
             "hint": "Criação de acessos · usuários · cadastros · senhas · ambientes",
             "separated": True},
        ],
        "scope_layers": [
            {"id": "vm122", "label": "Desk VM122", "host": "10.10.10.122", "desc": "Módulos internos"},
            {"id": "vm112", "label": "Onboard VM112", "host": "10.10.10.112", "desc": "Wizard, mail, API"},
            {"id": "vm123", "label": "Finance VM123", "host": "10.10.10.123", "desc": "FOSS, Odoo, OpenPanel"},
            {"id": "externas", "label": "Infra externa", "host": "—", "desc": "Cloudflare, Traefik, Proxmox…"},
        ],
        "service_labels": {
            "desk": "Desk VM122",
            "vm112": "VM112 Wizard",
            "vm123_foss": "FOSSBilling",
            "vm123_odoo": "Odoo 16",
            "vm123_openpanel": "OpenPanel",
            "infra": "Infra / SSH",
            "vm104": "Wazuh VM104",
        },
    }
