"""Tests for FastMCP server skeleton."""

from unittest.mock import patch

import pytest
from pytest_httpx import HTTPXMock

from midjourney_proxy_mcp.server import (
    VALID_STATUSES,
    get_image,
    get_status,
    imagine,
    list_images,
    main,
    mcp,
    resource_generation_by_id,
    resource_generations,
    resource_generations_by_status,
    resource_stats,
)


class TestServerSkeleton:
    """Tests for server skeleton."""

    def test_mcp_instance_exists(self) -> None:
        """Test that MCP instance is created."""
        assert mcp is not None
        assert mcp.name == "midjourney_mcp"

    def test_mcp_has_instructions(self) -> None:
        """Test that MCP has instructions."""
        assert mcp.instructions == "Generate Midjourney images via ImagineAPI"

    def test_main_function_exists(self) -> None:
        """Test that main function exists and is callable."""
        assert callable(main)

    def test_valid_statuses_defined(self) -> None:
        """Test that VALID_STATUSES contains expected values."""
        assert {"pending", "in-progress", "completed", "failed"} == VALID_STATUSES


@pytest.mark.asyncio
class TestListImagesValidation:
    """Tests for list_images status validation."""

    async def test_invalid_status_raises_error(self) -> None:
        """Invalid status raises ValueError with helpful message."""
        with pytest.raises(ValueError) as exc_info:
            await list_images(status="invalid-status")

        assert "Invalid status 'invalid-status'" in str(exc_info.value)
        assert "Allowed values:" in str(exc_info.value)


@pytest.mark.asyncio
class TestResourceGenerationsByStatusValidation:
    """Tests for resource_generations_by_status status validation."""

    async def test_invalid_status_raises_error(self) -> None:
        """Invalid status raises ValueError with helpful message."""
        with pytest.raises(ValueError) as exc_info:
            await resource_generations_by_status(status="invalid-status")

        assert "Invalid status 'invalid-status'" in str(exc_info.value)
        assert "Allowed values:" in str(exc_info.value)


# =============================================================================
# MCP Handler Tests (TDD)
# =============================================================================


@pytest.mark.asyncio
class TestImagineHandler:
    """Tests for imagine() MCP tool handler."""

    async def test_imagine_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """imagine() handler delegates to midjourney_imagine and returns result."""
        httpx_mock.add_response(
            method="POST",
            url="https://cl.imagineapi.dev/items/images",
            match_json={"prompt": "A beautiful sunset"},
            json={
                "data": {
                    "id": "img-123",
                    "prompt": "A beautiful sunset",
                    "status": "pending",
                    "result": None,
                    "url": None,
                    "results": None,
                    "progress": None,
                    "upscaled_urls": None,
                    "upscaled": None,
                    "ref": None,
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        result = await imagine(prompt="A beautiful sunset")

        assert result["id"] == "img-123"
        assert result["status"] == "pending"

    async def test_imagine_handler_with_ref(self, httpx_mock: HTTPXMock) -> None:
        """imagine() handler passes ref parameter correctly."""
        httpx_mock.add_response(
            method="POST",
            url="https://cl.imagineapi.dev/items/images",
            match_json={"prompt": "Test prompt", "ref": "my-ref"},
            json={
                "data": {
                    "id": "img-456",
                    "prompt": "Test prompt",
                    "status": "pending",
                    "result": None,
                    "url": None,
                    "results": None,
                    "progress": None,
                    "upscaled_urls": None,
                    "upscaled": None,
                    "ref": "my-ref",
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        result = await imagine(prompt="Test prompt", ref="my-ref")

        assert result["id"] == "img-456"


@pytest.mark.asyncio
class TestGetStatusHandler:
    """Tests for get_status() MCP tool handler."""

    async def test_get_status_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """get_status() handler returns image status info."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/img-123",
            json={
                "data": {
                    "id": "img-123",
                    "prompt": "A sunset",
                    "status": "completed",
                    "result": "https://cdn.imagineapi.dev/test.png",
                    "url": "https://cdn.imagineapi.dev/test.png",
                    "results": None,
                    "progress": 100,
                    "upscaled_urls": ["https://cdn.imagineapi.dev/u1.png"],
                    "upscaled": ["u1-id"],
                    "ref": None,
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        result = await get_status(image_id="img-123")

        assert result["id"] == "img-123"
        assert result["status"] == "completed"
        assert result["url"] == "https://cdn.imagineapi.dev/test.png"
        assert result["upscaled_urls"] == ["https://cdn.imagineapi.dev/u1.png"]


@pytest.mark.asyncio
class TestListImagesHandler:
    """Tests for list_images() MCP tool handler."""

    async def test_list_images_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """list_images() handler returns image list."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images?limit=10&offset=0",
            json={
                "data": [
                    {
                        "id": "img-1",
                        "prompt": "First image",
                        "status": "completed",
                        "result": "https://cdn.imagineapi.dev/1.png",
                        "url": "https://cdn.imagineapi.dev/1.png",
                        "results": None,
                        "progress": 100,
                        "upscaled_urls": None,
                        "upscaled": None,
                        "ref": None,
                        "error": None,
                        "user_created": "user-abc",
                        "date_created": "2024-01-01T00:00:00Z",
                    }
                ],
                "meta": {"total": 1},
            },
        )

        result = await list_images(limit=10)

        assert result["total"] == 1
        assert len(result["images"]) == 1

    async def test_list_images_handler_with_status_filter(self, httpx_mock: HTTPXMock) -> None:
        """list_images() handler filters by status."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images?limit=5&offset=0&filter%5Bstatus%5D%5B_eq%5D=completed",
            json={
                "data": [],
                "meta": {"total": 0},
            },
        )

        result = await list_images(limit=5, status="completed")

        assert result["total"] == 0
        assert result["images"] == []


@pytest.mark.asyncio
class TestResourceGenerationsHandler:
    """Tests for resource_generations() MCP resource handler."""

    async def test_resource_generations_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """resource_generations() handler returns all generations."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images?limit=100&offset=0",
            json={
                "data": [
                    {
                        "id": "img-1",
                        "prompt": "Test image",
                        "status": "completed",
                        "result": "https://cdn.imagineapi.dev/1.png",
                        "url": "https://cdn.imagineapi.dev/1.png",
                        "results": None,
                        "progress": 100,
                        "upscaled_urls": None,
                        "upscaled": None,
                        "ref": None,
                        "error": None,
                        "user_created": "user-abc",
                        "date_created": "2024-01-01T00:00:00Z",
                    }
                ],
                "meta": {"total": 1},
            },
        )

        result = await resource_generations()

        assert len(result) == 1
        assert result[0]["id"] == "img-1"


@pytest.mark.asyncio
class TestResourceGenerationsByStatusHandler:
    """Tests for resource_generations_by_status() MCP resource handler."""

    async def test_resource_generations_by_status_handler_success(
        self, httpx_mock: HTTPXMock
    ) -> None:
        """resource_generations_by_status() returns filtered generations."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images?limit=100&offset=0&filter%5Bstatus%5D%5B_eq%5D=pending",
            json={
                "data": [
                    {
                        "id": "img-pending",
                        "prompt": "Pending image",
                        "status": "pending",
                        "result": None,
                        "url": None,
                        "results": None,
                        "progress": None,
                        "upscaled_urls": None,
                        "upscaled": None,
                        "ref": None,
                        "error": None,
                        "user_created": "user-abc",
                        "date_created": "2024-01-01T00:00:00Z",
                    }
                ],
                "meta": {"total": 1},
            },
        )

        result = await resource_generations_by_status(status="pending")

        assert len(result) == 1
        assert result[0]["status"] == "pending"


@pytest.mark.asyncio
class TestResourceGenerationByIdHandler:
    """Tests for resource_generation_by_id() MCP resource handler."""

    async def test_resource_generation_by_id_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """resource_generation_by_id() returns single generation details."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/img-123",
            json={
                "data": {
                    "id": "img-123",
                    "prompt": "Detailed image",
                    "status": "completed",
                    "result": "https://cdn.imagineapi.dev/123.png",
                    "url": "https://cdn.imagineapi.dev/123.png",
                    "results": None,
                    "progress": 100,
                    "upscaled_urls": ["https://cdn.imagineapi.dev/u1.png"],
                    "upscaled": ["u1-id"],
                    "ref": "test-ref",
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        result = await resource_generation_by_id(id="img-123")

        assert result["id"] == "img-123"
        assert result["status"] == "completed"


@pytest.mark.asyncio
class TestResourceStatsHandler:
    """Tests for resource_stats() MCP resource handler."""

    async def test_resource_stats_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """resource_stats() returns generation statistics."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images?limit=100&offset=0",
            json={
                "data": [
                    {
                        "id": "img-1",
                        "prompt": "Image 1",
                        "status": "completed",
                        "result": "https://cdn.imagineapi.dev/1.png",
                        "url": "https://cdn.imagineapi.dev/1.png",
                        "results": None,
                        "progress": 100,
                        "upscaled_urls": None,
                        "upscaled": None,
                        "ref": None,
                        "error": None,
                        "user_created": "user-abc",
                        "date_created": "2024-01-01T00:00:00Z",
                    },
                    {
                        "id": "img-2",
                        "prompt": "Image 2",
                        "status": "pending",
                        "result": None,
                        "url": None,
                        "results": None,
                        "progress": None,
                        "upscaled_urls": None,
                        "upscaled": None,
                        "ref": None,
                        "error": None,
                        "user_created": "user-abc",
                        "date_created": "2024-01-01T00:00:00Z",
                    },
                ],
                "meta": {"total": 2},
            },
        )

        result = await resource_stats()

        assert result["total"] == 2
        assert result["by_status"]["completed"] == 1
        assert result["by_status"]["pending"] == 1
        assert result["completion_rate"] == 50.0


@pytest.mark.asyncio
class TestGetImageHandler:
    """Tests for get_image() MCP tool handler."""

    async def test_get_image_handler_success(self, httpx_mock: HTTPXMock) -> None:
        """get_image() returns Image object for completed image."""
        from mcp.server.fastmcp.utilities.types import Image

        image_bytes = b"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01"

        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/img-123",
            json={
                "data": {
                    "id": "img-123",
                    "prompt": "A beautiful sunset",
                    "status": "completed",
                    "result": "https://cdn.imagineapi.dev/images/result.png",
                    "url": "https://cdn.imagineapi.dev/images/result.png",
                    "results": None,
                    "progress": 100,
                    "upscaled_urls": None,
                    "upscaled": None,
                    "ref": None,
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        httpx_mock.add_response(
            method="GET",
            url="https://cdn.imagineapi.dev/images/result.png",
            content=image_bytes,
            headers={"Content-Type": "image/png"},
        )

        result = await get_image(image_id="img-123")

        assert isinstance(result, Image)


class TestMainFunction:
    """Tests for main() function."""

    def test_main_calls_mcp_run(self) -> None:
        """main() calls mcp.run()."""
        with patch.object(mcp, "run") as mock_run:
            main()
            mock_run.assert_called_once()
