"""Inventory CRUD, host maintenance, datastore files, DVS."""

from __future__ import annotations

from typing import Any

from fastapi import APIRouter, Depends, Query, Response

from app.db.pool import Database
from app.dependencies import get_database
from app.vsphere import inventory
from app.vsphere.domain import content, inventory_ops
from app.vsphere.errors import invalid_argument
from app.vsphere.security.authz import require_privilege, require_read
from app.vsphere.security.session import SessionInfo

router = APIRouter(tags=["vSphere Inventory Ext"])


def _require_name(body: dict[str, Any]) -> str:
    name = body.get("name")
    if not name:
        raise invalid_argument("name is required")
    return str(name)


@router.post("/api/vcenter/datacenter")
async def create_dc(
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Datacenter.Create")),
) -> str:
    return await inventory_ops.create_datacenter(
        database, name=_require_name(body), folder=str(body.get("folder") or "group-d1")
    )


@router.delete("/api/vcenter/datacenter/{datacenter}")
async def delete_dc(
    datacenter: str,
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Datacenter.Delete")),
) -> Response:
    await inventory_ops.delete_managed(database, datacenter)
    return Response(status_code=204)


@router.post("/api/vcenter/cluster")
async def create_cluster(
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Cluster.Create")),
) -> str:
    return await inventory_ops.create_cluster(
        database,
        name=_require_name(body),
        folder=str(body.get("folder") or "group-h23"),
        drs_enabled=bool((body.get("drs") or {}).get("enabled", True)),
        ha_enabled=bool((body.get("ha") or {}).get("enabled", True)),
    )


@router.delete("/api/vcenter/cluster/{cluster}")
async def delete_cluster(
    cluster: str,
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Cluster.Delete")),
) -> Response:
    await inventory_ops.delete_managed(database, cluster)
    return Response(status_code=204)


@router.post("/api/vcenter/folder")
async def create_folder(
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Folder.Create")),
) -> str:
    spec = body.get("create_spec") if isinstance(body.get("create_spec"), dict) else body
    return await inventory_ops.create_folder(
        database,
        name=_require_name(spec),
        parent=str(spec.get("parent") or spec.get("folder") or "group-v23"),
        folder_type=str(spec.get("type") or "VIRTUAL_MACHINE"),
    )


@router.post("/api/vcenter/folder/{folder}")
async def folder_action(
    folder: str,
    action: str = Query(...),
    body: dict[str, Any] | None = None,
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Folder.Rename")),
) -> Response:
    body = body or {}
    if action == "rename":
        await inventory_ops.rename_object(database, folder, _require_name(body))
    elif action == "move":
        parent = body.get("parent")
        if not parent:
            raise invalid_argument("parent is required")
        await inventory_ops.move_object(database, folder, str(parent))
    else:
        raise invalid_argument(f"unsupported action {action}")
    return Response(status_code=204)


@router.delete("/api/vcenter/folder/{folder}")
async def delete_folder(
    folder: str,
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Folder.Delete")),
) -> Response:
    await inventory_ops.delete_managed(database, folder)
    return Response(status_code=204)


@router.post("/api/vcenter/resource-pool")
async def create_rp(
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Resource.CreatePool")),
) -> str:
    return await inventory_ops.create_resource_pool(
        database, name=_require_name(body), parent=str(body.get("parent") or "resgroup-22")
    )


@router.delete("/api/vcenter/resource-pool/{resource_pool}")
async def delete_rp(
    resource_pool: str,
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Resource.DeletePool")),
) -> Response:
    await inventory_ops.delete_managed(database, resource_pool)
    return Response(status_code=204)


@router.post("/api/vcenter/host/{host}/maintenance")
async def host_maintenance(
    host: str,
    action: str = Query(...),
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Host.Config.Maintenance")),
) -> dict[str, Any]:
    if action not in {"enter", "exit"}:
        raise invalid_argument("action must be enter|exit")
    return await inventory_ops.set_host_maintenance(database, host, enabled=(action == "enter"))


@router.get("/api/vcenter/datastore/{datastore}/files")
async def ds_files(
    datastore: str,
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_read),
) -> list[dict[str, Any]]:
    return await content.list_datastore_files(database, datastore)


@router.post("/api/vcenter/datastore/{datastore}/files")
async def ds_put_file(
    datastore: str,
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Datastore.FileManagement")),
) -> Response:
    path = body.get("path")
    if not path:
        raise invalid_argument("path is required")
    await content.put_datastore_file(
        database,
        datastore,
        str(path),
        size=int(body.get("size") or 0),
        file_type=str(body.get("type") or "FILE"),
    )
    return Response(status_code=204)


@router.get("/api/vcenter/network/dvs")
async def list_dvs(
    database: Database = Depends(get_database), _: SessionInfo = Depends(require_read)
) -> list[dict[str, Any]]:
    objects = await inventory.list_objects(database, type_name="VmwareDistributedVirtualSwitch")
    return [{"dvs": o.moid, "name": o.name} for o in objects]


@router.post("/api/vcenter/network/dvs")
async def create_dvs(
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Network.Assign")),
) -> str:
    return await inventory_ops.create_dvs(
        database, name=_require_name(body), folder=str(body.get("folder") or "group-n23")
    )


@router.post("/api/vcenter/network/dvpg")
async def create_dvpg(
    body: dict[str, Any],
    database: Database = Depends(get_database),
    _: SessionInfo = Depends(require_privilege("Network.Assign")),
) -> str:
    dvs = body.get("dvs")
    if not dvs:
        raise invalid_argument("dvs is required")
    return await inventory_ops.create_dvpg(
        database,
        name=_require_name(body),
        dvs=str(dvs),
        vlan_id=int(body.get("vlan_id") or 0),
    )
