"""Tests for asynchronous AsyncOdinsEyeClient."""

from __future__ import annotations

import tempfile
from pathlib import Path

import pytest
from pytest_httpx import HTTPXMock

from odins_eye import AsyncOdinsEyeClient, OdinsEyeAPIError, OdinsEyeError
from odins_eye.client import RetryConfig


class TestAsyncClientInitialization:
    """Tests for async client initialization."""

    async def test_init_with_api_key(self, mock_api_key):
        """Test async client initialization with API key."""
        async with AsyncOdinsEyeClient(api_key=mock_api_key) as client:
            assert client._client.headers["api-key"] == mock_api_key

    async def test_init_without_api_key(self):
        """Test async client initialization without API key."""
        async with AsyncOdinsEyeClient() as client:
            assert "api-key" not in client._client.headers

    async def test_context_manager(self, mock_api_key):
        """Test async client as context manager."""
        async with AsyncOdinsEyeClient(api_key=mock_api_key) as client:
            assert isinstance(client, AsyncOdinsEyeClient)


class TestAsyncIndexEndpoint:
    """Tests for async index endpoint."""

    async def test_index_success(self, httpx_mock: HTTPXMock, mock_status_response):
        """Test successful async index call."""
        httpx_mock.add_response(json=mock_status_response)
        async with AsyncOdinsEyeClient() as client:
            result = await client.index()
            assert result["status"] == 200
            assert result["message"] == "API is running"

    async def test_index_http_error(self, httpx_mock: HTTPXMock):
        """Test async index call with HTTP error."""
        httpx_mock.add_response(
            status_code=500, json={"error": "Internal server error"}
        )
        async with AsyncOdinsEyeClient(
            retry_config=RetryConfig(max_retries=0)
        ) as client:
            with pytest.raises(OdinsEyeAPIError) as exc_info:
                await client.index()
            assert exc_info.value.status_code == 500


class TestAsyncDocumentEndpoint:
    """Tests for async document endpoint."""

    async def test_document_success(self, httpx_mock: HTTPXMock, mock_es_response):
        """Test successful async document retrieval."""
        httpx_mock.add_response(json=mock_es_response)
        async with AsyncOdinsEyeClient() as client:
            result = await client.document("doc123")
            assert result["statusCode"] == 200

    async def test_document_missing_id(self):
        """Test async document call without doc_id."""
        async with AsyncOdinsEyeClient() as client:
            with pytest.raises(ValueError, match="doc_id is required"):
                await client.document("")


class TestAsyncQueryEndpoint:
    """Tests for async query endpoint."""

    async def test_query_success(self, httpx_mock: HTTPXMock, mock_query_response):
        """Test successful async query."""
        httpx_mock.add_response(json=mock_query_response)
        async with AsyncOdinsEyeClient() as client:
            query_data = {"query": {"match_all": {}}}
            result = await client.query(query_data)
            assert result["status"] == 200


class TestAsyncProfileEndpoint:
    """Tests for async profile endpoint."""

    async def test_profile_success(self, httpx_mock: HTTPXMock, mock_profile_response):
        """Test successful async profile retrieval."""
        httpx_mock.add_response(json=mock_profile_response)
        async with AsyncOdinsEyeClient() as client:
            result = await client.profile()
            assert result["status"] == 200
            assert result["user"]["name"] == "Test User"


class TestAsyncVersionEndpoint:
    """Tests for async version endpoint."""

    async def test_version_success(self, httpx_mock: HTTPXMock, mock_version_response):
        """Test successful async version retrieval."""
        httpx_mock.add_response(json=mock_version_response)
        async with AsyncOdinsEyeClient() as client:
            result = await client.version()
            assert result["status"] == 200
            assert result["version"] == "1.0.0"


class TestAsyncCreditsEndpoint:
    """Tests for async credits endpoint."""

    async def test_credits_success(self, httpx_mock: HTTPXMock, mock_credits_response):
        """Test successful async credits retrieval."""
        httpx_mock.add_response(json=mock_credits_response)
        async with AsyncOdinsEyeClient() as client:
            result = await client.credits()
            assert result["status"] == 200
            assert result["current_balance"] == 1000


class TestAsyncFaceSearchEndpoint:
    """Tests for async face search endpoint."""

    async def test_face_search_success(self, httpx_mock: HTTPXMock):
        """Test successful async face search."""
        httpx_mock.add_response(json={"status": 200, "results": []})

        # Create a temporary image file
        with tempfile.NamedTemporaryFile(suffix=".jpg", delete=False) as tmp:
            tmp.write(b"fake image data")
            tmp_path = tmp.name

        try:
            async with AsyncOdinsEyeClient() as client:
                result = await client.face_search(tmp_path)
                assert result["status"] == 200
        finally:
            Path(tmp_path).unlink()

    async def test_face_search_file_not_found(self):
        """Test async face search with non-existent file."""
        async with AsyncOdinsEyeClient() as client:
            with pytest.raises(ValueError, match="image_path not found"):
                await client.face_search("/nonexistent/path.jpg")


class TestAsyncNettestEndpoint:
    """Tests for async nettest endpoint."""

    async def test_nettest_success(self, httpx_mock: HTTPXMock):
        """Test successful async network test."""
        httpx_mock.add_response(json={"status": "ok"})
        async with AsyncOdinsEyeClient() as client:
            result = await client.nettest()
            assert result["status"] == "ok"


class TestAsyncErrorHandling:
    """Tests for async error handling."""

    async def test_non_json_response(self, httpx_mock: HTTPXMock):
        """Test handling of non-JSON response."""
        httpx_mock.add_response(text="Not JSON")
        async with AsyncOdinsEyeClient() as client:
            with pytest.raises(OdinsEyeError, match="non-JSON response"):
                await client.index()

    async def test_validation_error(self, httpx_mock: HTTPXMock):
        """Test handling of validation error."""
        httpx_mock.add_response(json={"invalid": "data"})
        async with AsyncOdinsEyeClient() as client:
            with pytest.raises(OdinsEyeError, match="validation failed"):
                await client.profile()

    async def test_api_error_with_details(
        self, httpx_mock: HTTPXMock, mock_error_response
    ):
        """Test API error with error details."""
        httpx_mock.add_response(status_code=400, json=mock_error_response)
        async with AsyncOdinsEyeClient() as client:
            with pytest.raises(OdinsEyeAPIError) as exc_info:
                await client.index()
            assert exc_info.value.status_code == 400
            assert exc_info.value.error == "Invalid request"
