"""Deep-handler wire realism: seed non-empty, mutations, tasks, REST↔SOAP."""

from __future__ import annotations

import os

import pytest
from httpx import ASGITransport, AsyncClient

from app.config import Settings
from app.main import create_app
from app.vsphere.seed import seed_vsphere_inventory

pytestmark = pytest.mark.integration


@pytest.fixture
async def client() -> AsyncClient:
    database_url = os.getenv("TEST_DATABASE_URL") or os.getenv("DATABASE_URL")
    if not database_url:
        pytest.skip("TEST_DATABASE_URL / DATABASE_URL required")
    settings = Settings(
        database_url=database_url,  # type: ignore[arg-type]
        contract_snapshot=None,
        enable_pve_stub=False,
    )
    app = create_app(settings=settings, worker_factories=())
    async with app.router.lifespan_context(app):
        await seed_vsphere_inventory(app.state.database, force=True, profile="small")
        async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as http:
            yield http


async def _session(client: AsyncClient) -> dict[str, str]:
    login = await client.post(
        "/api/session",
        auth=("administrator@vsphere.local", "VMware1!"),
    )
    assert login.status_code == 201
    return {"vmware-api-session-id": login.json()}


async def test_deep_inventory_lists_and_details(client: AsyncClient) -> None:
    headers = await _session(client)
    hosts = await client.get("/api/vcenter/host", headers=headers)
    assert hosts.status_code == 200
    assert len(hosts.json()) >= 3
    host_id = hosts.json()[0]["host"]
    host = await client.get(f"/api/vcenter/host/{host_id}", headers=headers)
    assert host.status_code == 200
    assert host.json()["name"]

    stores = await client.get("/api/vcenter/datastore", headers=headers)
    assert stores.status_code == 200
    ds_id = stores.json()[0]["datastore"]
    detail = await client.get(f"/api/vcenter/datastore/{ds_id}", headers=headers)
    assert detail.status_code == 200
    files = await client.get(f"/api/vcenter/datastore/{ds_id}/files", headers=headers)
    assert files.status_code == 200
    assert len(files.json()) >= 1


async def test_content_library_deep_get_not_stub(client: AsyncClient) -> None:
    headers = await _session(client)
    libs = await client.get("/api/content/library", headers=headers)
    assert libs.status_code == 200
    assert "lib-local-1" in libs.json()

    local = await client.get("/api/content/local-library", headers=headers)
    assert local.status_code == 200
    assert "lib-local-1" in local.json()

    info = await client.get("/api/content/library/lib-local-1", headers=headers)
    assert info.status_code == 200
    body = info.json()
    assert body["id"] == "lib-local-1"
    assert body["name"] == "Local Content"
    assert body["type"] == "LOCAL"
    assert "path" not in body  # stub placeholder must not leak

    local_info = await client.get("/api/content/local-library/lib-local-1", headers=headers)
    assert local_info.status_code == 200
    assert local_info.json()["id"] == "lib-local-1"

    items = await client.get(
        "/api/content/library/item",
        params={"library_id": "lib-local-1"},
        headers=headers,
    )
    assert items.status_code == 200
    assert "item-ubuntu" in items.json()

    item = await client.get("/api/content/library/item/item-ubuntu", headers=headers)
    assert item.status_code == 200
    assert item.json()["name"] == "ubuntu-22.04"
    assert item.json()["library_id"] == "lib-local-1"


async def test_power_task_poll_and_soap_consistency(client: AsyncClient) -> None:
    headers = await _session(client)
    power = await client.post(
        "/api/vcenter/vm/vm-104/power",
        params={"action": "start"},
        headers=headers,
    )
    assert power.status_code == 200
    task_id = power.json()["task"]
    assert task_id.startswith("task-")

    task = await client.get(f"/api/cis/tasks/{task_id}", headers=headers)
    assert task.status_code == 200
    payload = task.json()
    assert payload["status"] == "SUCCEEDED"
    assert payload["state"] == "SUCCEEDED"
    assert isinstance(payload["description"], dict)
    assert payload["description"]["default_message"]
    assert isinstance(payload["progress"], dict)
    assert payload["progress"]["completed"] == 100
    assert payload["result"]["vm"] == "vm-104"

    listed = await client.post(
        "/api/cis/tasks",
        params={"action": "list"},
        headers=headers,
        json={"filter_spec": {"tasks": [task_id]}},
    )
    assert listed.status_code == 200
    assert task_id in listed.json()

    state = await client.get("/api/vcenter/vm/vm-104/power", headers=headers)
    assert state.json()["state"] == "POWERED_ON"

    soap = await client.post(
        "/sdk",
        content="""<?xml version="1.0"?>
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
          <soapenv:Body>
            <Login xmlns="urn:vim25">
              <_this type="SessionManager">SessionManager</_this>
              <userName>administrator@vsphere.local</userName>
              <password>VMware1!</password>
            </Login>
          </soapenv:Body>
        </soapenv:Envelope>""",
        headers={"Content-Type": "text/xml"},
    )
    assert soap.status_code == 200
    cookie = (soap.headers.get("set-cookie") or "").split(";")[0]
    power_soap = await client.post(
        "/sdk",
        content="""<?xml version="1.0"?>
        <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
          <soapenv:Body>
            <PowerOffVM_Task xmlns="urn:vim25">
              <_this type="VirtualMachine">vm-104</_this>
            </PowerOffVM_Task>
          </soapenv:Body>
        </soapenv:Envelope>""",
        headers={"Content-Type": "text/xml", "Cookie": cookie},
    )
    assert power_soap.status_code == 200
    assert "task-" in power_soap.text
    assert 'type="Task"' in power_soap.text


async def test_tagging_association_query_action(client: AsyncClient) -> None:
    headers = await _session(client)
    tags = await client.get("/api/cis/tagging/tag", headers=headers)
    assert tags.status_code == 200
    tag_id = tags.json()[0]
    attach = await client.post(
        "/api/cis/tagging/tag-association",
        params={"action": "attach"},
        headers=headers,
        json={"tag_id": tag_id, "object_id": {"type": "VirtualMachine", "id": "vm-103"}},
    )
    assert attach.status_code == 204
    listed = await client.post(
        "/api/cis/tagging/tag-association",
        params={"action": "list-attached-tags"},
        headers=headers,
        json={"object_id": {"type": "VirtualMachine", "id": "vm-103"}},
    )
    assert listed.status_code == 200
    assert tag_id in listed.json()


async def test_folder_create_and_authz_permissions(client: AsyncClient) -> None:
    headers = await _session(client)
    folder = await client.post(
        "/api/vcenter/folder",
        headers=headers,
        json={"name": "deep-repro-folder", "type": "VIRTUAL_MACHINE", "parent": "group-v23"},
    )
    assert folder.status_code == 200
    assert folder.json().startswith("group-")

    roles = await client.get("/api/vcenter/authorization/roles", headers=headers)
    assert roles.status_code == 200
    assert any(r["role"] == "Administrator" for r in roles.json())
    perms = await client.get("/api/vcenter/authorization/permissions", headers=headers)
    assert perms.status_code == 200
    assert len(perms.json()) >= 1


async def test_ovf_deploy_accepts_official_target_fields(client: AsyncClient) -> None:
    headers = await _session(client)
    deploy = await client.post(
        "/api/vcenter/ovf/library-item/item-ubuntu",
        headers=headers,
        json={
            "target": {
                "resource_pool_id": "resgroup-22",
                "folder_id": "group-v23",
                "host_id": "host-11",
                "datastore_id": "datastore-31",
            },
            "deployment_spec": {"name": "ovf-deep-repro", "accept_all_EULA": True},
        },
    )
    assert deploy.status_code == 200
    body = deploy.json()
    assert body["resource_id"]["type"] == "VirtualMachine"
    assert body["resource_id"]["id"].startswith("vm-")
    assert body["task"].startswith("task-")
    vm = await client.get(f"/api/vcenter/vm/{body['resource_id']['id']}", headers=headers)
    assert vm.status_code == 200
    assert vm.json()["name"] == "ovf-deep-repro"
