"""E2E test: Full agent workflow using the SDK.

This simulates what an AI agent would do with MCPGateway:
1. Create a sandbox (execution environment)
2. Import a server from catalog (to get MCP tools)
3. Create a skill and upload it
4. Search for tools using semantic search
5. Execute a tool
6. Clean up everything

Requires:
- Running backend with sandbox support (Docker-in-Docker)
- Real API key (not dev mode bypass)
- Embedding provider configured (for tool search)

Run with:
    E2E_TESTS_ENABLED=true SDK_API_KEY=mgw_... uv run pytest tests/integration/test_agent_workflow.py -v
"""

from __future__ import annotations

import os

import pytest

from mcpgateway_sdk import GatewayError, MCPGateway

GATEWAY_URL = os.environ.get("GATEWAY_URL", "http://localhost:8000")
SDK_API_KEY = os.environ.get("SDK_API_KEY", "")

pytestmark = [
    pytest.mark.asyncio,
    pytest.mark.skipif(
        not os.environ.get("E2E_TESTS_ENABLED"),
        reason="E2E tests disabled (set E2E_TESTS_ENABLED=true)",
    ),
    pytest.mark.skipif(
        not os.environ.get("SDK_API_KEY"),
        reason="Full agent workflow needs real API key (set SDK_API_KEY=mgw_...)",
    ),
]


@pytest.fixture
async def gw():
    """Provide an authenticated MCPGateway client with real API key."""
    async with MCPGateway(api_key=SDK_API_KEY, url=GATEWAY_URL) as client:
        yield client


# ------------------------------------------------------------------
# Test: Full agent workflow (sandbox → skill → tools → execute)
# ------------------------------------------------------------------


async def test_agent_full_workflow(gw: MCPGateway) -> None:
    """Simulate a complete agent workflow using the SDK.

    This is the most realistic E2E test — it does what an AI agent would do:
    1. Create a sandbox to run code in
    2. Import a time server from catalog
    3. Create a simple skill
    4. List tools from the server
    5. Execute a tool via the SDK
    6. Clean everything up
    """
    sandbox_id = None
    server_id = None
    skill_id = None

    try:
        # Step 1: Create a sandbox
        sandbox = await gw.sandboxes.create(image="mcpgateway/sandbox-runtime:latest")
        sandbox_id = sandbox.id
        assert sandbox.status in ("running", "creating", "pending")
        assert sandbox.id is not None

        # Step 2: Import a time server from catalog
        catalog = await gw.servers.catalog_search("time")
        assert len(catalog) > 0, "No 'time' entries in catalog"

        entry = None
        for c in catalog:
            if c.get("registry") and c.get("registry_id"):
                entry = c
                break
        assert entry is not None, "No catalog entry with registry + registry_id"

        server = await gw.servers.import_from_catalog(
            registry=entry["registry"],
            registry_id=entry["registry_id"],
            name="sdk-agent-workflow-test",
        )
        server_id = server.id
        assert server.id is not None

        # Step 3: Create a simple skill
        # Note: description in frontmatter MUST match the description parameter
        skill_desc = "Test skill from SDK E2E"
        skill_md = f"""---
name: sdk-test-skill
description: {skill_desc}
version: "1.0"
---

# SDK Test Skill

This skill was created by the MCPGateway Python SDK integration test.
"""
        skill = await gw.skills.create(
            name="sdk-test-skill",
            skill_md_content=skill_md,
            description=skill_desc,
        )
        skill_id = skill.id
        assert skill.id is not None
        assert skill.name == "sdk-test-skill"

        # Step 4: List tools from the imported server
        tools = await gw.servers.list_tools(server.id)
        assert isinstance(tools, list)
        # Tools may be empty if server hasn't synced yet — that's ok for the test

        # Step 5: Get skill details
        detail = await gw.skills.get(skill.id)
        assert detail.id == skill.id
        assert detail.name == "sdk-test-skill"
        assert detail.description == "Test skill from SDK E2E"

        # Step 6: Execute command in sandbox
        exec_result = await gw.sandboxes.exec(
            sandbox.id, "python3 -c \"print('Hello from SDK E2E test')\"", timeout=30
        )
        assert exec_result.exit_code == 0
        assert "Hello from SDK E2E test" in exec_result.stdout

        # Step 7: Upload a file to sandbox
        await gw.sandboxes.upload(
            sandbox.id, "/workspace/test.txt", b"SDK E2E test content"
        )

        # Step 8: Download the file back
        content = await gw.sandboxes.download(sandbox.id, "/workspace/test.txt")
        assert content == b"SDK E2E test content"

        # Step 9: List files in sandbox
        files = await gw.sandboxes.list_files(sandbox.id, path="/workspace")
        assert isinstance(files, list)
        file_names = [f.name for f in files]
        assert "test.txt" in file_names

    finally:
        # Cleanup: delete everything in reverse order
        if skill_id:
            try:
                await gw.skills.delete(skill_id)
            except GatewayError:
                pass

        if server_id:
            try:
                await gw.servers.delete(server_id)
            except GatewayError:
                pass

        if sandbox_id:
            try:
                await gw.sandboxes.destroy(sandbox_id)
            except GatewayError:
                pass


# ------------------------------------------------------------------
# Test: Sandbox lifecycle (create → exec → files → stop → resume → destroy)
# ------------------------------------------------------------------


async def test_sandbox_full_lifecycle(gw: MCPGateway) -> None:
    """Test complete sandbox lifecycle via SDK."""
    sandbox_id = None

    try:
        # Create
        sandbox = await gw.sandboxes.create()
        sandbox_id = sandbox.id
        assert sandbox.status in ("running", "creating", "pending")

        # Execute code
        result = await gw.sandboxes.exec(
            sandbox.id, "echo 'SDK lifecycle test' && python3 --version"
        )
        assert result.exit_code == 0
        assert "SDK lifecycle test" in result.stdout

        # Upload file
        await gw.sandboxes.upload(sandbox.id, "/workspace/data.json", b'{"test": true}')

        # Download file
        data = await gw.sandboxes.download(sandbox.id, "/workspace/data.json")
        assert b'"test"' in data

        # List files
        files = await gw.sandboxes.list_files(sandbox.id)
        assert any(f.name == "data.json" for f in files)

        # Stop
        try:
            await gw.sandboxes.stop(sandbox.id)
        except GatewayError:
            pass  # Stop may not be supported in all runtimes

        # Resume
        try:
            resumed = await gw.sandboxes.resume(sandbox.id)
            assert isinstance(resumed, dict) or hasattr(resumed, "id")
        except GatewayError:
            pass  # Resume may not be supported

    finally:
        if sandbox_id:
            try:
                await gw.sandboxes.destroy(sandbox_id)
            except GatewayError:
                pass


# ------------------------------------------------------------------
# Test: Skill CRUD lifecycle (create → get → update → download → delete)
# ------------------------------------------------------------------


async def test_skill_crud_lifecycle(gw: MCPGateway) -> None:
    """Test complete skill CRUD via SDK."""
    skill_id = None

    try:
        # Create — frontmatter description must match parameter
        crud_desc = "CRUD test skill"
        skill = await gw.skills.create(
            name="sdk-crud-test",
            skill_md_content=f"---\nname: sdk-crud-test\ndescription: {crud_desc}\n---\n# Test",
            description=crud_desc,
        )
        skill_id = skill.id
        assert skill.name == "sdk-crud-test"

        # Get
        fetched = await gw.skills.get(skill.id)
        assert fetched.id == skill.id
        assert fetched.description == "CRUD test skill"

        # Update
        updated = await gw.skills.update(skill.id, description="Updated description")
        assert updated.description == "Updated description"

        # Download package
        package = await gw.skills.download_package(skill.id)
        assert isinstance(package, bytes)
        assert len(package) > 0  # Should be a ZIP file

        # List — our skill should appear
        skills = await gw.skills.list(search="sdk-crud-test")
        assert any(s.id == skill.id for s in skills)

    finally:
        if skill_id:
            try:
                await gw.skills.delete(skill_id)
            except GatewayError:
                pass


# ------------------------------------------------------------------
# Test: API key management
# ------------------------------------------------------------------


async def test_api_key_crud(gw: MCPGateway) -> None:
    """Test API key create → list → get → revoke via SDK."""
    key_id = None

    try:
        # Create
        key = await gw.auth.create_api_key(name="sdk-key-test")
        key_id = key.id
        assert key.name == "sdk-key-test"
        assert key.key is not None  # Secret shown once on creation

        # List
        keys = await gw.auth.list_api_keys()
        assert any(k.id == key.id for k in keys)

        # Get
        fetched = await gw.auth.get_api_key(key.id)
        assert fetched.id == key.id
        assert fetched.name == "sdk-key-test"

    finally:
        if key_id:
            try:
                await gw.auth.revoke_api_key(key_id)
            except GatewayError:
                pass
