"""Unit tests for RestoreJobs namespace."""

from __future__ import annotations

from unittest.mock import MagicMock

import httpx
import pytest
import respx

from pinecone.__interface__.restore_jobs import RestoreJobNamespaceProtocol
from pinecone._internal.http import AsyncHTTPClient, HTTPClient, HTTPConfig
from pinecone.async_client.restore_jobs import AsyncRestoreJobs
from pinecone.client.restore_jobs import RestoreJobs


pytestmark = pytest.mark.unit


class TestRestoreJobsProtocolCompliance:
    """Tests for protocol compliance."""

    def test_restore_jobs_satisfies_protocol(self):
        """Test that RestoreJobs class satisfies RestoreJobNamespaceProtocol."""
        http_client = MagicMock(spec=HTTPClient)
        restore_jobs = RestoreJobs(http_client=http_client)

        assert isinstance(restore_jobs, RestoreJobNamespaceProtocol)

    def test_async_restore_jobs_satisfies_protocol(self):
        """Test that AsyncRestoreJobs class satisfies AsyncRestoreJobNamespaceProtocol."""
        from pinecone.__interface__.restore_jobs import AsyncRestoreJobNamespaceProtocol

        http_client = MagicMock(spec=AsyncHTTPClient)
        restore_jobs = AsyncRestoreJobs(http_client=http_client)

        assert isinstance(restore_jobs, AsyncRestoreJobNamespaceProtocol)


@respx.mock
class TestRestoreJobsList:
    """Tests for list() method."""

    @pytest.fixture()
    def restore_jobs(self) -> RestoreJobs:
        """Create RestoreJobs instance with real HTTP client."""
        client = HTTPClient(api_key="test-key", config=HTTPConfig(http2=False))
        return RestoreJobs(http_client=client)

    def test_list_success(self, restore_jobs: RestoreJobs):
        """Test successful list operation."""
        respx.get("https://api.pinecone.io/restore-jobs").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-1",
                            "backup_id": "backup-1",
                            "target_index_name": "my-index",
                            "target_index_id": "idx-1",
                            "status": "Completed",
                            "created_at": "2025-02-04T13:00:00Z",
                            "completed_at": "2025-02-04T14:00:00Z",
                            "percent_complete": 100.0,
                        }
                    ],
                    "pagination": None,
                },
            )
        )

        jobs = list(restore_jobs.list())

        assert len(jobs) == 1
        assert jobs[0].restore_job_id == "job-1"
        assert jobs[0].status == "Completed"
        assert jobs[0].percent_complete == 100.0

    def test_list_empty_results(self, restore_jobs: RestoreJobs):
        """Test list with no restore jobs."""
        respx.get("https://api.pinecone.io/restore-jobs").mock(
            return_value=httpx.Response(200, json={"data": [], "pagination": None})
        )

        jobs = list(restore_jobs.list())

        assert len(jobs) == 0

    def test_list_fetches_multiple_pages(self, restore_jobs: RestoreJobs):
        """Test that list() fetches all pages automatically."""
        # Mock first page
        respx.get("https://api.pinecone.io/restore-jobs").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-1",
                            "backup_id": "backup-1",
                            "target_index_name": "my-index",
                            "target_index_id": "idx-1",
                            "status": "Completed",
                            "created_at": "2025-02-04T13:00:00Z",
                            "completed_at": "2025-02-04T14:00:00Z",
                            "percent_complete": 100.0,
                        }
                    ],
                    "pagination": {"next": "token-123"},
                },
            )
        )

        # Mock second page (with pagination token)
        respx.get("https://api.pinecone.io/restore-jobs?paginationToken=token-123").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-2",
                            "backup_id": "backup-2",
                            "target_index_name": "my-index-2",
                            "target_index_id": "idx-2",
                            "status": "InProgress",
                            "created_at": "2025-02-04T15:00:00Z",
                            "percent_complete": 50.0,
                        }
                    ],
                    "pagination": None,  # Last page
                },
            )
        )

        jobs = list(restore_jobs.list())

        # Should have fetched both pages
        assert len(jobs) == 2
        assert jobs[0].restore_job_id == "job-1"
        assert jobs[1].restore_job_id == "job-2"

    def test_list_with_pagination_structure(self, restore_jobs: RestoreJobs):
        """Test list handles pagination structure (single page, no next token)."""
        respx.get("https://api.pinecone.io/restore-jobs").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-2",
                            "backup_id": "backup-2",
                            "target_index_name": "my-index-2",
                            "target_index_id": "idx-2",
                            "status": "InProgress",
                            "created_at": "2025-02-04T15:00:00Z",
                            "percent_complete": 50.0,
                        }
                    ],
                    "pagination": {},  # No next token - final page
                },
            )
        )

        jobs = list(restore_jobs.list())

        assert len(jobs) == 1
        assert jobs[0].restore_job_id == "job-2"
        assert jobs[0].percent_complete == 50.0

    def test_list_validates_positive_limit(self, restore_jobs: RestoreJobs):
        """Test that list validates limit is positive."""
        with pytest.raises(ValueError, match="limit must be a positive integer"):
            restore_jobs.list(limit=0)

        with pytest.raises(ValueError, match="limit must be a positive integer"):
            restore_jobs.list(limit=-1)


@respx.mock
class TestRestoreJobsDescribe:
    """Tests for describe() method."""

    @pytest.fixture()
    def restore_jobs(self) -> RestoreJobs:
        """Create RestoreJobs instance with real HTTP client."""
        client = HTTPClient(api_key="test-key", config=HTTPConfig(http2=False))
        return RestoreJobs(http_client=client)

    def test_describe_success(self, restore_jobs: RestoreJobs):
        """Test successful describe operation."""
        job_id = "job-1"
        respx.get(f"https://api.pinecone.io/restore-jobs/{job_id}").mock(
            return_value=httpx.Response(
                200,
                json={
                    "restore_job_id": job_id,
                    "backup_id": "backup-1",
                    "target_index_name": "my-index",
                    "target_index_id": "idx-1",
                    "status": "InProgress",
                    "created_at": "2025-02-04T13:00:00Z",
                    "percent_complete": 42.5,
                },
            )
        )

        job = restore_jobs.describe(job_id)

        assert job.restore_job_id == job_id
        assert job.status == "InProgress"
        assert job.percent_complete == 42.5

    def test_describe_completed_job(self, restore_jobs: RestoreJobs):
        """Test describe for completed job with all fields."""
        job_id = "job-completed"
        respx.get(f"https://api.pinecone.io/restore-jobs/{job_id}").mock(
            return_value=httpx.Response(
                200,
                json={
                    "restore_job_id": job_id,
                    "backup_id": "backup-1",
                    "target_index_name": "my-index",
                    "target_index_id": "idx-1",
                    "status": "Completed",
                    "created_at": "2025-02-04T13:00:00Z",
                    "completed_at": "2025-02-04T14:00:00Z",
                    "percent_complete": 100.0,
                },
            )
        )

        job = restore_jobs.describe(job_id)

        assert job.restore_job_id == job_id
        assert job.status == "Completed"
        assert job.completed_at == "2025-02-04T14:00:00Z"
        assert job.percent_complete == 100.0

    def test_describe_in_progress_no_completed_at(self, restore_jobs: RestoreJobs):
        """Test describe for in-progress job without completed_at."""
        job_id = "job-in-progress"
        respx.get(f"https://api.pinecone.io/restore-jobs/{job_id}").mock(
            return_value=httpx.Response(
                200,
                json={
                    "restore_job_id": job_id,
                    "backup_id": "backup-1",
                    "target_index_name": "my-index",
                    "target_index_id": "idx-1",
                    "status": "InProgress",
                    "created_at": "2025-02-04T13:00:00Z",
                    "percent_complete": 50.0,
                    # No completed_at field
                },
            )
        )

        job = restore_jobs.describe(job_id)

        assert job.completed_at is None
        assert job.percent_complete == 50.0

    def test_describe_validates_empty_job_id(self, restore_jobs: RestoreJobs):
        """Test that describe validates empty job_id."""
        with pytest.raises(ValueError, match="job_id"):
            restore_jobs.describe("")


@respx.mock
class TestAsyncRestoreJobsList:
    """Tests for async list() method."""

    @pytest.fixture()
    def async_restore_jobs(self) -> AsyncRestoreJobs:
        """Create AsyncRestoreJobs instance with real HTTP client."""
        client = AsyncHTTPClient(api_key="test-key", config=HTTPConfig(http2=False))
        return AsyncRestoreJobs(http_client=client)

    @pytest.mark.asyncio()
    async def test_list_success(self, async_restore_jobs: AsyncRestoreJobs):
        """Test successful async list operation."""
        respx.get("https://api.pinecone.io/restore-jobs").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-1",
                            "backup_id": "backup-1",
                            "target_index_name": "my-index",
                            "target_index_id": "idx-1",
                            "status": "Completed",
                            "created_at": "2025-02-04T13:00:00Z",
                            "completed_at": "2025-02-04T14:00:00Z",
                            "percent_complete": 100.0,
                        }
                    ],
                    "pagination": None,
                },
            )
        )

        jobs = []
        async for job in async_restore_jobs.list():
            jobs.append(job)

        assert len(jobs) == 1
        assert jobs[0].restore_job_id == "job-1"
        assert jobs[0].status == "Completed"
        assert jobs[0].percent_complete == 100.0

    @pytest.mark.asyncio()
    async def test_list_validates_positive_limit(self, async_restore_jobs: AsyncRestoreJobs):
        """Test that async list validates limit is positive."""
        with pytest.raises(ValueError, match="limit must be a positive integer"):
            async_restore_jobs.list(limit=0)


@respx.mock
class TestAsyncRestoreJobsDescribe:
    """Tests for async describe() method."""

    @pytest.fixture()
    def async_restore_jobs(self) -> AsyncRestoreJobs:
        """Create AsyncRestoreJobs instance with real HTTP client."""
        client = AsyncHTTPClient(api_key="test-key", config=HTTPConfig(http2=False))
        return AsyncRestoreJobs(http_client=client)

    @pytest.mark.asyncio()
    async def test_describe_success(self, async_restore_jobs: AsyncRestoreJobs):
        """Test successful async describe operation."""
        job_id = "job-1"
        respx.get(f"https://api.pinecone.io/restore-jobs/{job_id}").mock(
            return_value=httpx.Response(
                200,
                json={
                    "restore_job_id": job_id,
                    "backup_id": "backup-1",
                    "target_index_name": "my-index",
                    "target_index_id": "idx-1",
                    "status": "InProgress",
                    "created_at": "2025-02-04T13:00:00Z",
                    "percent_complete": 42.5,
                },
            )
        )

        job = await async_restore_jobs.describe(job_id)

        assert job.restore_job_id == job_id
        assert job.status == "InProgress"
        assert job.percent_complete == 42.5

    @pytest.mark.asyncio()
    async def test_describe_validates_empty_job_id(self, async_restore_jobs: AsyncRestoreJobs):
        """Test that async describe validates empty job_id."""
        with pytest.raises(ValueError, match="job_id"):
            await async_restore_jobs.describe("")

    @pytest.mark.asyncio()
    async def test_list_fetches_multiple_pages(self, async_restore_jobs: AsyncRestoreJobs):
        """Test that async list() fetches all pages automatically."""
        # Mock first page
        respx.get("https://api.pinecone.io/restore-jobs").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-1",
                            "backup_id": "backup-1",
                            "target_index_name": "my-index",
                            "target_index_id": "idx-1",
                            "status": "Completed",
                            "created_at": "2025-02-04T13:00:00Z",
                            "completed_at": "2025-02-04T14:00:00Z",
                            "percent_complete": 100.0,
                        }
                    ],
                    "pagination": {"next": "token-123"},
                },
            )
        )

        # Mock second page
        respx.get("https://api.pinecone.io/restore-jobs?paginationToken=token-123").mock(
            return_value=httpx.Response(
                200,
                json={
                    "data": [
                        {
                            "restore_job_id": "job-2",
                            "backup_id": "backup-2",
                            "target_index_name": "my-index-2",
                            "target_index_id": "idx-2",
                            "status": "InProgress",
                            "created_at": "2025-02-04T15:00:00Z",
                            "percent_complete": 50.0,
                        }
                    ],
                    "pagination": None,
                },
            )
        )

        jobs = []
        async for job in async_restore_jobs.list():
            jobs.append(job)

        assert len(jobs) == 2
        assert jobs[0].restore_job_id == "job-1"
        assert jobs[1].restore_job_id == "job-2"


class TestRestoreJobsRepr:
    """Tests for __repr__ methods."""

    def test_sync_repr(self):
        """Test sync RestoreJobs __repr__."""
        http_client = MagicMock(spec=HTTPClient)
        restore_jobs = RestoreJobs(http_client=http_client, base_url="https://api.pinecone.io")

        repr_str = repr(restore_jobs)

        assert "RestoreJobs" in repr_str
        assert "https://api.pinecone.io" in repr_str

    def test_async_repr(self):
        """Test async AsyncRestoreJobs __repr__."""
        http_client = MagicMock(spec=AsyncHTTPClient)
        restore_jobs = AsyncRestoreJobs(http_client=http_client, base_url="https://api.pinecone.io")

        repr_str = repr(restore_jobs)

        assert "AsyncRestoreJobs" in repr_str
        assert "https://api.pinecone.io" in repr_str
