"""Tests for ImagineAPI client."""

import httpx
import pytest
from pytest_httpx import HTTPXMock

from midjourney_proxy_mcp.client import ImagineAPIClient, ImagineAPIError
from midjourney_proxy_mcp.models import ImageRequest, ImageStatus


class TestImagineAPIClient:
    """Tests for ImagineAPIClient."""

    def test_token_required(self, monkeypatch: pytest.MonkeyPatch) -> None:
        """Test that token is required."""
        from midjourney_proxy_mcp import config

        monkeypatch.setattr(config.settings, "token", "")
        with pytest.raises(ValueError, match="ImagineAPI token is required"):
            ImagineAPIClient(token="")

    def test_client_with_token(self) -> None:
        """Test client initialization with token."""
        client = ImagineAPIClient(token="test-token")
        assert client.token == "test-token"
        assert client.base_url == "https://cl.imagineapi.dev"

    def test_custom_base_url(self) -> None:
        """Test client with custom base URL."""
        client = ImagineAPIClient(
            base_url="https://custom.api.dev/",
            token="test-token",
        )
        assert client.base_url == "https://custom.api.dev"

    def test_base_url_trailing_slash_removed(self) -> None:
        """Test that trailing slash is removed from base URL."""
        client = ImagineAPIClient(
            base_url="https://api.example.com///",
            token="test-token",
        )
        assert client.base_url == "https://api.example.com"


class TestImagineAPIError:
    """Tests for ImagineAPIError."""

    def test_error_with_status_code(self) -> None:
        """Test error with status code."""
        error = ImagineAPIError(
            message="Not found",
            status_code=404,
            response_body='{"error": "not found"}',
        )
        assert str(error) == "Not found"
        assert error.status_code == 404
        assert error.response_body == '{"error": "not found"}'

    def test_error_without_status_code(self) -> None:
        """Test error without status code."""
        error = ImagineAPIError(message="Connection failed")
        assert str(error) == "Connection failed"
        assert error.status_code is None
        assert error.response_body is None

    def test_from_response(self) -> None:
        """Test creating error from httpx response."""
        response = httpx.Response(
            status_code=500,
            content=b'{"error": "internal server error"}',
        )
        error = ImagineAPIError.from_response("create image", response)
        assert "Failed to create image: HTTP 500" in str(error)
        assert error.status_code == 500


class TestImagineAPIClientHTTP:
    """HTTP integration tests for ImagineAPIClient."""

    @pytest.fixture
    def client(self) -> ImagineAPIClient:
        """Create a client for testing."""
        return ImagineAPIClient(
            base_url="https://cl.imagineapi.dev",
            token="test-token",
        )

    async def test_create_image_success(
        self, client: ImagineAPIClient, httpx_mock: HTTPXMock
    ) -> None:
        """Test successful image creation."""
        httpx_mock.add_response(
            method="POST",
            url="https://cl.imagineapi.dev/items/images",
            match_json={"prompt": "A beautiful sunset", "ref": "my-ref"},
            json={
                "data": {
                    "id": "img-123",
                    "prompt": "A beautiful sunset",
                    "status": "pending",
                    "result": None,
                    "url": None,
                    "progress": None,
                    "upscaled_urls": None,
                    "upscaled": None,
                    "ref": "my-ref",
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        async with client:
            request = ImageRequest(prompt="A beautiful sunset", ref="my-ref")
            result = await client.create_image(request)

        assert result.id == "img-123"
        assert result.prompt == "A beautiful sunset"
        assert result.status == ImageStatus.PENDING
        assert result.ref == "my-ref"

    async def test_create_image_api_error(
        self, client: ImagineAPIClient, httpx_mock: HTTPXMock
    ) -> None:
        """Test image creation API error handling."""
        httpx_mock.add_response(
            method="POST",
            url="https://cl.imagineapi.dev/items/images",
            status_code=400,
            json={"error": "Invalid prompt"},
        )

        async with client:
            request = ImageRequest(prompt="test")
            with pytest.raises(ImagineAPIError) as exc_info:
                await client.create_image(request)

        assert exc_info.value.status_code == 400

    async def test_get_image_success(self, client: ImagineAPIClient, httpx_mock: HTTPXMock) -> None:
        """Test successful image retrieval."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/img-456",
            json={
                "data": {
                    "id": "img-456",
                    "prompt": "A majestic mountain",
                    "status": "completed",
                    "result": "https://cdn.imagineapi.dev/test.png",
                    "url": "https://cdn.imagineapi.dev/test.png",
                    "progress": 100,
                    "upscaled_urls": ["https://cdn.imagineapi.dev/u1.png"],
                    "upscaled": ["u1-id"],
                    "ref": None,
                    "error": None,
                    "user_created": "user-xyz",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        async with client:
            result = await client.get_image("img-456")

        assert result.id == "img-456"
        assert result.status == ImageStatus.COMPLETED
        assert result.result == "https://cdn.imagineapi.dev/test.png"
        assert result.progress == 100

    async def test_get_image_not_found(
        self, client: ImagineAPIClient, httpx_mock: HTTPXMock
    ) -> None:
        """Test image not found error."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/not-exist",
            status_code=404,
            json={"error": "Not found"},
        )

        async with client:
            with pytest.raises(ImagineAPIError) as exc_info:
                await client.get_image("not-exist")

        assert exc_info.value.status_code == 404
        assert "Image not found" in str(exc_info.value)

    async def test_list_images_success(
        self, client: ImagineAPIClient, httpx_mock: HTTPXMock
    ) -> None:
        """Test successful image listing."""
        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={"limit": "10", "offset": "0"},
            ),
            json={
                "data": [
                    {
                        "id": "img-1",
                        "prompt": "Test 1",
                        "status": "completed",
                        "result": "https://cdn.imagineapi.dev/1.png",
                    },
                    {
                        "id": "img-2",
                        "prompt": "Test 2",
                        "status": "pending",
                        "result": None,
                    },
                ],
                "meta": {"total": 2},
            },
        )

        async with client:
            result = await client.list_images(limit=10, offset=0)

        assert len(result.data) == 2
        assert result.data[0].id == "img-1"
        assert result.data[1].id == "img-2"
        assert result.meta == {"total": 2}

    async def test_list_images_with_status_filter(
        self, client: ImagineAPIClient, httpx_mock: HTTPXMock
    ) -> None:
        """Test image listing with status filter."""
        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={
                    "limit": "25",
                    "offset": "0",
                    "filter[status][_eq]": "completed",
                },
            ),
            json={
                "data": [
                    {
                        "id": "img-1",
                        "prompt": "Test 1",
                        "status": "completed",
                        "result": "https://cdn.imagineapi.dev/1.png",
                    },
                ],
            },
        )

        async with client:
            result = await client.list_images(status="completed")

        assert len(result.data) == 1
        assert result.data[0].status == ImageStatus.COMPLETED

    async def test_client_context_manager(self, httpx_mock: HTTPXMock) -> None:
        """Test client async context manager lifecycle."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/test",
            json={
                "data": {
                    "id": "test",
                    "prompt": "test",
                    "status": "pending",
                }
            },
        )

        client = ImagineAPIClient(token="test-token")
        assert client._client is None

        async with client:
            assert client._client is not None
            await client.get_image("test")

        assert client._client is None
