"""Tests for query tools (get_status, list_images, get_image)."""

import httpx
import pytest
from pytest_httpx import HTTPXMock

from midjourney_proxy_mcp.tools import (
    midjourney_get_image,
    midjourney_get_status,
    midjourney_list_images,
)

pytestmark = pytest.mark.asyncio


class TestMidjourneyGetStatus:
    """Tests for midjourney_get_status function."""

    async def test_get_status_pending(self, httpx_mock: HTTPXMock) -> None:
        """대기 중인 이미지 상태 조회."""
        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": "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 midjourney_get_status(image_id="img-123")

        assert result["id"] == "img-123"
        assert result["status"] == "pending"
        assert "progress" not in result
        assert "url" not in result
        assert "upscaled_urls" not in result

    async def test_get_status_in_progress(self, httpx_mock: HTTPXMock) -> None:
        """진행 중인 이미지 상태 조회 (progress 포함)."""
        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": "in-progress",
                    "result": None,
                    "url": None,
                    "results": None,
                    "progress": 50,
                    "upscaled_urls": None,
                    "upscaled": None,
                    "ref": None,
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

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

        assert result["id"] == "img-123"
        assert result["status"] == "in-progress"
        assert result["progress"] == 50
        assert "url" not in result

    async def test_get_status_completed(self, httpx_mock: HTTPXMock) -> None:
        """완료된 이미지 상태 조회 (url, upscaled_urls 포함)."""
        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/images/result.png",
                    "url": "https://cdn.imagineapi.dev/images/result.png",
                    "results": None,
                    "progress": 100,
                    "upscaled_urls": [
                        "https://cdn.imagineapi.dev/images/u1.png",
                        "https://cdn.imagineapi.dev/images/u2.png",
                        "https://cdn.imagineapi.dev/images/u3.png",
                        "https://cdn.imagineapi.dev/images/u4.png",
                    ],
                    "upscaled": ["u1-id", "u2-id", "u3-id", "u4-id"],
                    "ref": "my-ref",
                    "error": None,
                    "user_created": "user-xyz",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        result = await midjourney_get_status(image_id="img-456")

        assert result["id"] == "img-456"
        assert result["status"] == "completed"
        assert result["url"] == "https://cdn.imagineapi.dev/images/result.png"
        assert len(result["upscaled_urls"]) == 4
        assert "progress" not in result

    async def test_get_status_failed(self, httpx_mock: HTTPXMock) -> None:
        """실패한 이미지 상태 조회 (error 포함)."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/img-789",
            json={
                "data": {
                    "id": "img-789",
                    "prompt": "Invalid prompt",
                    "status": "failed",
                    "result": None,
                    "url": None,
                    "results": None,
                    "progress": None,
                    "upscaled_urls": None,
                    "upscaled": None,
                    "ref": None,
                    "error": "Prompt contains banned content",
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        result = await midjourney_get_status(image_id="img-789")

        assert result["id"] == "img-789"
        assert result["status"] == "failed"
        assert result["error"] == "Prompt contains banned content"
        assert "url" not in result

    async def test_get_status_not_found(self, httpx_mock: HTTPXMock) -> None:
        """존재하지 않는 이미지 조회 시 에러."""
        from midjourney_proxy_mcp.client import ImagineAPIError

        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/not-exist",
            status_code=404,
            json={"error": "Not found"},
        )

        with pytest.raises(ImagineAPIError) as exc_info:
            await midjourney_get_status(image_id="not-exist")

        assert exc_info.value.status_code == 404


class TestMidjourneyListImages:
    """Tests for midjourney_list_images function."""

    async def test_list_images_default(self, httpx_mock: HTTPXMock) -> None:
        """기본 파라미터로 이미지 목록 조회."""
        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": "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",
                    },
                    {
                        "id": "img-2",
                        "prompt": "Second 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-02T00:00:00Z",
                    },
                ],
                "meta": {"total": 2},
            },
        )

        result = await midjourney_list_images()

        assert result["total"] == 2
        assert len(result["images"]) == 2
        assert result["images"][0]["id"] == "img-1"
        assert result["images"][0]["status"] == "completed"
        assert result["images"][0]["url"] == "https://cdn.imagineapi.dev/1.png"
        assert result["images"][1]["id"] == "img-2"
        assert "url" not in result["images"][1]

    async def test_list_images_with_limit(self, httpx_mock: HTTPXMock) -> None:
        """limit 파라미터로 이미지 목록 조회."""
        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={"limit": "5", "offset": "0"},
            ),
            json={"data": [], "meta": {"total": 0}},
        )

        result = await midjourney_list_images(limit=5)

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

    async def test_list_images_with_status_filter(self, httpx_mock: HTTPXMock) -> None:
        """status 필터로 이미지 목록 조회."""
        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={
                    "limit": "10",
                    "offset": "0",
                    "filter[status][_eq]": "completed",
                },
            ),
            json={
                "data": [
                    {
                        "id": "img-completed",
                        "prompt": "Completed image",
                        "status": "completed",
                        "result": "https://cdn.imagineapi.dev/completed.png",
                        "url": "https://cdn.imagineapi.dev/completed.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 midjourney_list_images(status="completed")

        assert result["total"] == 1
        assert result["images"][0]["status"] == "completed"

    async def test_list_images_truncates_long_prompt(self, httpx_mock: HTTPXMock) -> None:
        """긴 프롬프트는 100자로 자름."""
        long_prompt = "A" * 150

        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={"limit": "10", "offset": "0"},
            ),
            json={
                "data": [
                    {
                        "id": "img-long",
                        "prompt": long_prompt,
                        "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": None,
            },
        )

        result = await midjourney_list_images()

        assert len(result["images"][0]["prompt"]) == 103
        assert result["images"][0]["prompt"].endswith("...")

    async def test_list_images_limit_bounds(self, httpx_mock: HTTPXMock) -> None:
        """limit은 1-100 범위로 제한됨."""
        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={"limit": "100", "offset": "0"},
            ),
            json={"data": [], "meta": None},
        )

        await midjourney_list_images(limit=200)

        httpx_mock.add_response(
            method="GET",
            url=httpx.URL(
                "https://cl.imagineapi.dev/items/images",
                params={"limit": "1", "offset": "0"},
            ),
            json={"data": [], "meta": None},
        )

        await midjourney_list_images(limit=-5)


class TestMidjourneyGetImage:
    """Tests for midjourney_get_image function."""

    async def test_get_image_returns_image_object(self, httpx_mock: HTTPXMock) -> None:
        """완료된 이미지 조회 시 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 midjourney_get_image(image_id="img-123")

        assert isinstance(result, Image)

    async def test_get_image_with_upscale_index(self, httpx_mock: HTTPXMock) -> None:
        """업스케일 인덱스로 특정 이미지 조회."""
        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-456",
            json={
                "data": {
                    "id": "img-456",
                    "prompt": "A majestic mountain",
                    "status": "completed",
                    "result": "https://cdn.imagineapi.dev/images/result.png",
                    "url": "https://cdn.imagineapi.dev/images/result.png",
                    "results": None,
                    "progress": 100,
                    "upscaled_urls": [
                        "https://cdn.imagineapi.dev/images/u1.png",
                        "https://cdn.imagineapi.dev/images/u2.png",
                        "https://cdn.imagineapi.dev/images/u3.png",
                        "https://cdn.imagineapi.dev/images/u4.png",
                    ],
                    "upscaled": ["u1-id", "u2-id", "u3-id", "u4-id"],
                    "ref": None,
                    "error": None,
                    "user_created": "user-xyz",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

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

        result = await midjourney_get_image(image_id="img-456", upscale_index=1)

        assert isinstance(result, Image)

    async def test_get_image_not_completed_raises_error(self, httpx_mock: HTTPXMock) -> None:
        """완료되지 않은 이미지 조회 시 에러."""
        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/img-pending",
            json={
                "data": {
                    "id": "img-pending",
                    "prompt": "A 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",
                }
            },
        )

        with pytest.raises(ValueError) as exc_info:
            await midjourney_get_image(image_id="img-pending")

        assert "not completed" in str(exc_info.value).lower()

    async def test_get_image_invalid_upscale_index(self, httpx_mock: HTTPXMock) -> None:
        """잘못된 업스케일 인덱스 시 에러."""
        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": [
                        "https://cdn.imagineapi.dev/images/u1.png",
                        "https://cdn.imagineapi.dev/images/u2.png",
                    ],
                    "upscaled": None,
                    "ref": None,
                    "error": None,
                    "user_created": "user-abc",
                    "date_created": "2024-01-01T00:00:00Z",
                }
            },
        )

        with pytest.raises(ValueError) as exc_info:
            await midjourney_get_image(image_id="img-123", upscale_index=5)

        assert "index" in str(exc_info.value).lower()

    async def test_get_image_not_found(self, httpx_mock: HTTPXMock) -> None:
        """존재하지 않는 이미지 조회 시 에러."""
        from midjourney_proxy_mcp.client import ImagineAPIError

        httpx_mock.add_response(
            method="GET",
            url="https://cl.imagineapi.dev/items/images/not-exist",
            status_code=404,
            json={"error": "Not found"},
        )

        with pytest.raises(ImagineAPIError) as exc_info:
            await midjourney_get_image(image_id="not-exist")

        assert exc_info.value.status_code == 404


@pytest.mark.integration
class TestMidjourneyQueryIntegration:
    """Integration tests for query tools (requires IMAGINEAPI_TOKEN)."""

    async def test_list_images_real_api(self) -> None:
        """실제 API로 이미지 목록 조회."""
        result = await midjourney_list_images(limit=5)

        assert "images" in result
        assert "total" in result
        assert isinstance(result["images"], list)
