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

This module provides 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 (
    RestoreJobInfoProtocol,
    RestoreJobNamespaceProtocol,
)
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 Page, Paginator


if TYPE_CHECKING:
    from pinecone._internal.http import HTTPClient


logger = get_logger(__name__)


class RestoreJobs(InteractiveIntrospectionMixin, RestoreJobNamespaceProtocol):
    """Implementation of restore job monitoring operations.

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

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

    Example:
        >>> from pinecone import Pinecone
        >>> pc = Pinecone(api_key="...")
        >>> restore_jobs = pc.restore_jobs
        >>>
        >>> # List all restore jobs
        >>> for job in restore_jobs.list():
        ...     print(f"{job.restore_job_id}: {job.status} ({job.percent_complete}%)")
        >>>
        >>> # Monitor a specific job
        >>> job = 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}%")
    """

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

        Args:
            http_client: 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,
    ) -> Paginator[RestoreJobInfoProtocol]:
        """List all restore jobs in the project.

        This method returns a 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:
            Paginator 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
            >>> for job in restore_jobs.list():
            ...     print(f"{job.restore_job_id}: {job.status}")

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

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

        Example resuming pagination:
            >>> first_page = next(restore_jobs.list().pages())
            >>> if first_page.pagination_token:
            ...     remaining = restore_jobs.list(pagination_token=first_page.pagination_token)
            ...     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,
        )

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

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

                response = 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 Paginator(
            fetch_page=fetch_page,
            initial_token=pagination_token,
            limit=limit,
            item_type="RestoreJobModel",
        )

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

        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 = 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 = 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 = 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 = 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"RestoreJobs(base_url='{self._base_url}')"
