"""Async Restore Jobs namespace implementation for monitoring restore operations.

This module provides async read-only access to restore job information. Restore jobs
are created automatically when restoring indexes from backups.
"""

from __future__ import annotations

from typing import TYPE_CHECKING, cast

import orjson

from pinecone.__interface__.restore_jobs import AsyncRestoreJobNamespaceProtocol
from pinecone._internal.adapters.restore_jobs_adapter import RestoreJobsAdapter
from pinecone._internal.constants import CONTROL_PLANE_API_VERSION
from pinecone._internal.introspection import InteractiveIntrospectionMixin
from pinecone._internal.logging import get_logger
from pinecone._internal.validation import require_non_empty
from pinecone.models.pagination import AsyncPaginator, Page


if TYPE_CHECKING:
    from pinecone.__interface__.restore_jobs import RestoreJobInfoProtocol
    from pinecone._internal.http import AsyncHTTPClient


logger = get_logger(__name__)


class AsyncRestoreJobs(InteractiveIntrospectionMixin, AsyncRestoreJobNamespaceProtocol):
    """Async implementation of restore job monitoring operations.

    This class provides async read-only access to restore job information, enabling
    concurrent job monitoring operations. Restore jobs are created automatically when
    you restore an index from a backup using the backups.create_index_from_backup()
    method.

    Args:
        http_client: Async HTTP client for making API requests
        base_url: Base URL for the Control Plane API

    Example:
        >>> from pinecone import AsyncPinecone
        >>> import asyncio
        >>>
        >>> async def main():
        ...     async with AsyncPinecone(api_key="...") as pc:
        ...         # List all restore jobs
        ...         async for job in pc.restore_jobs.list():
        ...             print(f"{job.restore_job_id}: {job.status} ({job.percent_complete}%)")
        ...
        ...         # Monitor a specific job
        ...         job = await pc.restore_jobs.describe("670e8400-e29b-41d4-a716-446655440001")
        ...         print(f"Restoring {job.target_index_name} from backup {job.backup_id}")
        ...         print(f"Progress: {job.percent_complete}%")
        >>>
        >>> asyncio.run(main())

    Example with concurrent operations:
        >>> async def monitor_jobs(pc, job_ids):
        ...     tasks = [pc.restore_jobs.describe(job_id) for job_id in job_ids]
        ...     return await asyncio.gather(*tasks)
    """

    def __init__(
        self,
        http_client: AsyncHTTPClient,
        base_url: str = "https://api.pinecone.io",
    ):
        """Initialize async RestoreJobs namespace.

        Args:
            http_client: Async HTTP client for making API requests
            base_url: Base URL for the Control Plane API. Defaults to production endpoint.
        """
        self._http = http_client
        self._base_url = base_url
        self._adapter = RestoreJobsAdapter()
        self._headers = {"X-Pinecone-Api-Version": CONTROL_PLANE_API_VERSION}

    def list(
        self,
        *,
        limit: int | None = None,
        pagination_token: str | None = None,
    ) -> AsyncPaginator[RestoreJobInfoProtocol]:
        """List all restore jobs in the project asynchronously.

        This method returns an async paginator that lazily fetches restore jobs.
        Iterate directly over the paginator to get individual jobs, or use .pages()
        for page-level access.

        Args:
            limit: Maximum number of items to return (across all pages). If not
                specified, all jobs will be returned.
            pagination_token: Token to resume pagination from a previous call.

        Returns:
            AsyncPaginator over RestoreJobInfo objects. Iterate directly for items,
            or use .pages() for page-level access.

        Raises:
            ValueError: If limit is not a positive integer.
            APIError: If the API returns an error response.
            APIConnectionError: If the request fails to connect.

        Example:
            >>> # List all restore jobs
            >>> async for job in restore_jobs.list():
            ...     print(f"{job.restore_job_id}: {job.status}")

        Example with pagination control:
            >>> # Get first 10 jobs
            >>> async for job in restore_jobs.list(limit=10):
            ...     print(job.restore_job_id)

        Example with page-level access:
            >>> async for page in restore_jobs.list().pages():
            ...     print(f"Got {len(page.items)} jobs")

        Example resuming pagination:
            >>> first_page = await anext(restore_jobs.list().pages())
            >>> if first_page.pagination_token:
            ...     remaining = restore_jobs.list(pagination_token=first_page.pagination_token)
            ...     async for job in remaining:
            ...         print(job.restore_job_id)
        """
        # Validate inputs
        if limit is not None and limit <= 0:
            raise ValueError("limit must be a positive integer")

        logger.info(
            "Listing restore jobs",
            limit=limit,
            has_pagination_token=pagination_token is not None,
        )

        async def fetch_page(token: str | None) -> Page[RestoreJobInfoProtocol]:
            """Fetch a page of restore jobs asynchronously."""
            logger.info("Fetching restore jobs page", pagination_token=token)

            try:
                params: dict[str, str] = {}
                if token:
                    params["paginationToken"] = token

                response = await self._http.get(
                    f"{self._base_url}/restore-jobs",
                    headers=self._headers,
                    params=params,
                )

                # Parse response once
                data = orjson.loads(response.content)
                jobs = self._adapter.to_restore_job_list(data)

                logger.debug(
                    "Successfully fetched restore jobs",
                    job_count=len(jobs),
                )

                # Extract pagination token
                items = cast("list[RestoreJobInfoProtocol]", jobs)
                next_token = (data.get("pagination") or {}).get("next")

                return Page(items=items, pagination_token=next_token)

            except Exception:
                logger.exception("Failed to list restore jobs")
                raise

        return AsyncPaginator(
            fetch_page=fetch_page,
            initial_token=pagination_token,
            limit=limit,
            item_type="RestoreJobModel",
        )

    async def describe(self, job_id: str) -> RestoreJobInfoProtocol:
        """Get details of a specific restore job asynchronously.

        This method retrieves complete metadata for a restore job including status,
        progress, and timing information.

        Args:
            job_id: Unique identifier of the restore job (UUID format). Get this from
                the restore_job_id field returned when creating an index from a backup,
                or from the list() operation.

        Returns:
            RestoreJobInfo with complete job metadata including:
                - restore_job_id: Unique identifier
                - backup_id: ID of the backup being restored
                - target_index_name: Name of the index being restored to
                - target_index_id: ID of the target index
                - status: Current status (Pending, InProgress, Completed, Failed)
                - created_at: ISO 8601 timestamp when job was created
                - completed_at: ISO 8601 timestamp when job completed (None if in progress)
                - percent_complete: Progress percentage (0-100, None if not available)

        Raises:
            ValueError: If job_id is empty.
            APIError: If the API returns an error (including 404 if not found).
            APIConnectionError: If the request fails to connect.

        Example:
            >>> job = await restore_jobs.describe("670e8400-e29b-41d4-a716-446655440001")
            >>> print(f"Status: {job.status}")
            >>> print(f"Progress: {job.percent_complete}%")
            >>> if job.completed_at:
            ...     print(f"Completed: {job.completed_at}")

        Example checking status:
            >>> job = await restore_jobs.describe(job_id)
            >>> if job.status == "Completed":
            ...     print("Restore is complete")
            ... elif job.status == "InProgress":
            ...     print(f"Restore in progress: {job.percent_complete}%")
            ... elif job.status == "Failed":
            ...     print("Restore failed")

        Example with error handling:
            >>> from pinecone.exceptions import APIError
            >>> try:
            ...     job = await restore_jobs.describe("invalid-id")
            ... except APIError as e:
            ...     if e.status_code == 404:
            ...         print("Job not found")
            ...     else:
            ...         print(f"API error: {e}")
        """
        # Validate inputs
        require_non_empty("job_id", job_id)

        logger.info("Describing restore job", job_id=job_id)

        try:
            response = await self._http.get(
                f"{self._base_url}/restore-jobs/{job_id}",
                headers=self._headers,
            )

            # Parse response
            data = orjson.loads(response.content)
            job = self._adapter.to_restore_job_model(data)

            logger.debug(
                "Successfully fetched restore job",
                job_id=job_id,
                status=job.status,
            )

            return cast("RestoreJobInfoProtocol", job)

        except Exception:
            logger.exception("Failed to describe restore job", job_id=job_id)
            raise

    def __repr__(self) -> str:
        """Return developer-friendly representation."""
        return f"AsyncRestoreJobs(base_url='{self._base_url}')"
