"""Lab-grade NSX / WCP / vSAN / identity / VECS / NFC state (DB-backed)."""

from __future__ import annotations

import json
import secrets
from typing import Any

from app.db.pool import Database
from app.vsphere import inventory
from app.vsphere.domain import api_state

_IDENTITY = "/api/vcenter/identity/providers"


def default_identity_providers() -> list[dict[str, Any]]:
    return [
        {
            "provider": "vsphere.local",
            "name": "vsphere.local",
            "type_id": "LocalOS",
            "domain_names": ["vsphere.local"],
            "is_default": True,
        },
        {
            "provider": "oidc-lab",
            "name": "Lab OIDC",
            "type_id": "Oidc",
            "issuer_uri": "https://idp.lab.local/realms/vsphere",
            "client_id": "vcenter-lab",
            "is_default": False,
        },
        {
            "provider": "saml-lab",
            "name": "Lab SAML",
            "type_id": "Saml",
            "idp_entity_id": "https://idp.lab.local/saml",
            "sso_service_url": "https://idp.lab.local/saml/sso",
            "is_default": False,
        },
    ]


def default_nsx_surface() -> dict[str, Any]:
    return {
        ("GET", "/api/vcenter/namespace-management/nsx-tier0-gateway"): [
            {
                "gateway": "nsx-tier0-1",
                "name": "tier0-lab",
                "path": "/infra/tier-0s/tier0-lab",
                "status": "UP",
            }
        ],
        ("GET", "/api/vcenter/namespace-management/networks/{network}/nsx/projects"): [
            {
                "project": "nsx-project-1",
                "name": "default",
                "path": "/orgs/default/projects/default",
                "status": "READY",
            }
        ],
        ("GET", "/api/vcenter/namespace-management/networks/{network}/nsx/edges"): [
            {
                "edge": "nsx-edge-1",
                "name": "edge-lab-1",
                "path": "/infra/sites/default/enforcement-points/default/edge-clusters/edge-1",
                "status": "UP",
            }
        ],
        (
            "GET",
            "/api/vcenter/namespace-management/networks/{network}/nsx/distributed-switches",
        ): [
            {
                "distributed_switch": "nsx-dvs-1",
                "name": "NSX-DVS",
                "path": "/infra/sites/default/enforcement-points/default/transport-zones/tz-1",
                "status": "UP",
            }
        ],
        ("GET", "/api/vcenter/namespace-management/networks/{network}/nsx/vpcs"): [
            {
                "vpc": "vpc-lab-1",
                "name": "vpc-lab",
                "path": "/orgs/default/projects/default/vpcs/vpc-lab",
                "status": "READY",
            }
        ],
        (
            "GET",
            "/api/vcenter/namespace-management/networks/{network}/nsx/vpc-connectivity-profiles",
        ): [
            {
                "profile": "vpc-profile-1",
                "name": "default-connectivity",
                "status": "READY",
            }
        ],
        (
            "GET",
            "/api/vcenter/namespaces/{namespace}/networks/{network}/nsx/subnets",
        ): [
            {
                "subnet": "subnet-lab-1",
                "name": "workload",
                "cidr": "10.244.0.0/24",
                "status": "READY",
            }
        ],
    }


def default_wcp_surface() -> dict[str, Any]:
    return {
        ("GET", "/api/vcenter/namespace-management/networks"): [
            {
                "network": "network-41",
                "name": "VM Network",
                "mode": "NSXT_VPC",
                "status": "READY",
            }
        ],
        ("GET", "/api/vcenter/namespaces"): [
            {
                "namespace": "ns-lab-1",
                "name": "ns-lab-1",
                "cluster": "domain-c21",
                "config_status": "RUNNING",
                "stats": {"cpu_used": 2, "memory_used_mib": 4096},
            }
        ],
        ("GET", "/api/vcenter/namespace-management/virtual-machine-classes"): [
            {
                "id": "best-effort-small",
                "cpu_count": 2,
                "memory_mb": 2048,
                "description": "Lab small class",
            },
            {
                "id": "guaranteed-large",
                "cpu_count": 8,
                "memory_mb": 16384,
                "description": "Lab large class",
            },
        ],
        ("GET", "/api/vcenter/namespace-management/clusters/{cluster}/nsm"): {
            "cluster": "domain-c21",
            "config_status": "RUNNING",
            "kubernetes_status": "READY",
            "network_provider": "NSXT_CONTAINER_PLUGIN",
        },
        (
            "GET",
            "/api/vcenter/namespace-management/supervisors/{supervisor}/identity/providers",
        ): [
            {
                "provider": "oidc-supervisor",
                "name": "Supervisor OIDC",
                "issuer": "https://idp.lab.local/realms/supervisor",
                "type": "OIDC",
                "status": "READY",
            }
        ],
        ("GET", "/api/vcenter/namespace-management/infrastructure-policies"): [
            {
                "policy": "infra-policy-lab-1",
                "name": "default-infra",
                "status": "ENABLED",
            }
        ],
    }


def default_vsan_surface() -> dict[str, Any]:
    return {
        ("GET", "/api/vcenter/storage/policies"): [
            {
                "policy": "policy-default",
                "name": "vSAN Default Storage Policy",
                "description": "Lab vSAN default",
                "policy_type": "VSAN",
            },
            {
                "policy": "policy-thin",
                "name": "Thin provision",
                "description": "Thin disks",
                "policy_type": "VVOL",
            },
            {
                "policy": "policy-vsan-raid1",
                "name": "vSAN RAID1",
                "description": "Failures to tolerate = 1",
                "policy_type": "VSAN",
            },
        ],
        ("GET", "/api/vcenter/storage/policies/{policy}"): {
            "policy": "policy-default",
            "name": "vSAN Default Storage Policy",
            "description": "Lab vSAN default",
            "policy_type": "VSAN",
            "constraints": [{"property_name": "hostFailuresToTolerate", "value": 1}],
        },
    }


def default_vecs_surface() -> dict[str, Any]:
    return {
        ("GET", "/api/vcenter/certificate-management/vcenter/tls-csr"): {
            "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBLabCSR\n-----END CERTIFICATE REQUEST-----",
            "status": "AVAILABLE",
            "subject_dn": "CN=vcenter.lab.local",
        },
        ("GET", "/api/vcenter/certificate-management/vcenter/signing-certificate"): {
            "cert": "-----BEGIN CERTIFICATE-----\nMIIBSigning\n-----END CERTIFICATE-----",
            "valid_from": "2026-01-01T00:00:00.000Z",
            "valid_to": "2030-01-01T00:00:00.000Z",
            "subject_dn": "CN=CA,DC=vsphere,DC=local",
        },
        ("GET", "/api/vcenter/certificate-management/vcenter/trusted-root-chains"): [
            {
                "chain": "chain-lab-1",
                "cert_chain": ["-----BEGIN CERTIFICATE-----\nMIIBRoot\n-----END CERTIFICATE-----"],
                "thumbprint": "AA:BB:CC:DD:EE:FF:00:11:22:33:44:55:66:77:88:99:AA:BB:CC:DD",
            }
        ],
        (
            "GET",
            "/api/vcenter/namespace-management/supervisors/{supervisor}/certificates",
        ): [
            {
                "certificate": "supervisor-tls",
                "status": "VALID",
                "valid_to": "2028-01-01T00:00:00.000Z",
            }
        ],
        (
            "GET",
            "/api/vcenter/namespace-management/supervisors/{supervisor}/signing-requests",
        ): [
            {
                "request": "csr-supervisor-1",
                "status": "PENDING",
                "csr": "-----BEGIN CERTIFICATE REQUEST-----\nMIIBSupCSR\n-----END CERTIFICATE REQUEST-----",
            }
        ],
    }


async def seed_platform_surface(database: Database) -> dict[str, int]:
    """Overlay rich lab payloads for previously shallow product areas (seed-time only)."""

    rows = 0
    providers = default_identity_providers()
    await api_state.put_seed_payload(database, "GET", _IDENTITY, providers)
    rows += 1

    for mapping in (
        default_nsx_surface(),
        default_wcp_surface(),
        default_vsan_surface(),
        default_vecs_surface(),
    ):
        for (verb, path), payload in mapping.items():
            await api_state.put_seed_payload(database, verb, path, payload)
            rows += 1
    return {"platform_surface_rows": rows}


async def list_identity_providers(database: Database) -> list[dict[str, Any]]:
    payload = await api_state.get_payload_or_seed(database, "GET", _IDENTITY)
    if not isinstance(payload, list) or not payload:
        return []
    if not any(str(item.get("provider")) == "vsphere.local" for item in payload):
        restored = await api_state.restore_seed_payload(database, "GET", _IDENTITY)
        if isinstance(restored, list) and restored:
            return restored
    return payload


async def get_identity_provider(database: Database, provider: str) -> dict[str, Any] | None:
    for item in await list_identity_providers(database):
        if provider in {
            str(item.get("provider")),
            str(item.get("name")),
            str(item.get("id")),
        }:
            return item
    return None


async def upsert_identity_provider(database: Database, body: dict[str, Any]) -> dict[str, Any]:
    providers = await list_identity_providers(database)
    provider_id = str(body.get("provider") or body.get("name") or f"idp-{secrets.token_hex(3)}")
    entry = {
        "provider": provider_id,
        "name": str(body.get("name") or provider_id),
        "type_id": str(body.get("type_id") or body.get("type") or "Oidc"),
        "is_default": bool(body.get("is_default", False)),
        **{
            k: v
            for k, v in body.items()
            if k not in {"provider", "name", "type_id", "type", "is_default"}
        },
    }
    out: list[dict[str, Any]] = []
    replaced = False
    for item in providers:
        if str(item.get("provider")) == provider_id:
            out.append({**item, **entry})
            replaced = True
        else:
            out.append(item)
    if not replaced:
        out.append(entry)
    await api_state.put_payload(database, "GET", _IDENTITY, out)
    return entry


async def delete_identity_provider(database: Database, provider: str) -> bool:
    providers = await list_identity_providers(database)
    filtered = [p for p in providers if str(p.get("provider")) != provider]
    if len(filtered) == len(providers):
        return False
    # Soft-delete lab baseline: restore seed document so GET stays non-empty.
    await api_state.restore_seed_payload(database, "GET", _IDENTITY)
    return True


def _decode_payload(value: Any) -> dict[str, Any]:
    current = value
    while isinstance(current, str):
        current = json.loads(current)
    return current if isinstance(current, dict) else {}


async def _save_nfc_lease(database: Database, lease_id: str, info: dict[str, Any]) -> None:
    pool = database.pool  # type: ignore[attr-defined]
    async with pool.acquire() as conn:
        await conn.execute(
            """
            INSERT INTO vsphere_nfc_leases (id, vm_moid, state, payload, updated_at)
            VALUES ($1, $2, $3, $4::jsonb, now())
            ON CONFLICT (id) DO UPDATE SET
              vm_moid = EXCLUDED.vm_moid,
              state = EXCLUDED.state,
              payload = EXCLUDED.payload,
              updated_at = now()
            """,
            lease_id,
            str(info.get("entity") or ""),
            str(info.get("state") or "ready"),
            json.dumps(info),
        )
    await inventory.upsert_object(
        database,
        moid=lease_id,
        type_name="HttpNfcLease",
        name=lease_id,
        parent_moid=None,
        props=info,
    )


async def create_nfc_lease(
    database: Database,
    *,
    vm: str,
    files: list[str] | None = None,
) -> dict[str, Any]:
    lease_id = f"lease-{secrets.token_hex(6)}"
    file_list = files or [f"{vm}.vmdk", f"{vm}.nvram"]
    info = {
        "lease": lease_id,
        "state": "ready",
        "entity": vm,
        "initializeProgress": 100,
        "transferProgress": 0,
        "info": {
            "deviceUrl": [
                {
                    "key": f"disk-{index}",
                    "importKey": name,
                    "url": f"https://localhost/nfc/{lease_id}/files/{name}",
                    "sslThumbprint": "https://example.invalid/thumbprint",
                }
                for index, name in enumerate(file_list)
            ]
        },
        "files": {name: {"uploaded": False, "size": 0} for name in file_list},
    }
    await _save_nfc_lease(database, lease_id, info)
    return info


async def get_nfc_lease(database: Database, lease_id: str) -> dict[str, Any] | None:
    pool = database.pool  # type: ignore[attr-defined]
    async with pool.acquire() as conn:
        row = await conn.fetchrow(
            "SELECT payload FROM vsphere_nfc_leases WHERE id = $1",
            lease_id,
        )
    if row is None:
        return None
    return _decode_payload(row["payload"])


async def complete_nfc_lease(database: Database, lease_id: str) -> dict[str, Any] | None:
    lease = await get_nfc_lease(database, lease_id)
    if lease is None:
        return None
    lease["state"] = "done"
    lease["transferProgress"] = 100
    await _save_nfc_lease(database, lease_id, lease)
    return lease


async def upload_nfc_file(
    database: Database,
    lease_id: str,
    filename: str,
    size: int,
) -> dict[str, Any] | None:
    lease = await get_nfc_lease(database, lease_id)
    if lease is None:
        return None
    files = lease.setdefault("files", {})
    files[filename] = {"uploaded": True, "size": size}
    uploaded = sum(1 for meta in files.values() if meta.get("uploaded"))
    total = max(len(files), 1)
    lease["transferProgress"] = int(100 * uploaded / total)
    if uploaded >= total:
        lease["state"] = "done"
    await _save_nfc_lease(database, lease_id, lease)
    return lease
