"""Docker Registry v2 API client.

Provides high-level interface for Docker Registry v2 operations
including image manifest management, layer operations, and repository catalog.
"""

from typing import Dict, Any, List

from ..auth.blackant_auth import BlackAntAuth
from ..http.client import HTTPClient, HTTPConnectionError
from ..exceptions import BlackAntDockerError
from ..utils.logging import get_logger


class DockerRegistryClient:
    """Docker Registry v2 API client.

    Provides operations for managing Docker images in a registry,
    including manifest operations, layer management, and repository catalog.

    Args:
        auth (BlackAntAuth): Authentication object with credentials.
        registry_url (str): Registry base URL.

    Examples:
        >>> auth = BlackAntAuth(user="my_name", password="xxx")
        >>> registry = DockerRegistryClient(auth=auth,
        ...     registry_url="http://localhost:5000")
        >>> catalog = registry.get_catalog()
        >>> manifest = registry.get_manifest("myapp", "latest")
    """

    def __init__(self, auth: BlackAntAuth, registry_url: str):
        """Initialize Docker Registry client.

        Args:
            auth: BlackAntAuth object with user credentials.
            registry_url: Docker Registry base URL.
        """
        self.auth = auth
        self.registry_url = registry_url.rstrip("/")

        # Initialize HTTPClient for registry operations
        self.http_client = HTTPClient(
            base_url=self.registry_url,
            auth_token_store=auth.token_store
        )

        self.logger = get_logger("docker.registry")
        self.logger.info(f"DockerRegistryClient initialized for {registry_url}")

    def get_catalog(self) -> List[str]:
        """Get repository catalog from registry.

        Returns:
            List of repository names.

        Raises:
            BlackAntDockerError: If catalog retrieval fails.
        """
        try:
            response = self.http_client.send_request(
                endpoint="/v2/_catalog",
                method="GET"
            )
            response.raise_for_status()

            catalog_data = response.json()
            repositories = catalog_data.get("repositories", [])

            self.logger.debug(f"Found {len(repositories)} repositories")
            return repositories

        except HTTPConnectionError as error:
            self.logger.error(f"Failed to get catalog: {error}")
            raise BlackAntDockerError(f"Could not get catalog: {error}") from error
        except Exception as error:
            self.logger.error(f"Unexpected error getting catalog: {error}")
            raise BlackAntDockerError(f"Catalog retrieval failed: {error}") from error

    def get_tags(self, repository: str) -> List[str]:
        """Get tags for a repository.

        Args:
            repository: Repository name.

        Returns:
            List of tags for the repository.

        Raises:
            BlackAntDockerError: If tag retrieval fails.
        """
        try:
            response = self.http_client.send_request(
                endpoint=f"/v2/{repository}/tags/list",
                method="GET"
            )
            response.raise_for_status()

            tags_data = response.json()
            tags = tags_data.get("tags", [])

            self.logger.debug(f"Found {len(tags)} tags for {repository}")
            return tags

        except HTTPConnectionError as error:
            self.logger.error(f"Failed to get tags for {repository}: {error}")
            raise BlackAntDockerError(f"Could not get tags: {error}") from error
        except Exception as error:
            self.logger.error(f"Unexpected error getting tags: {error}")
            raise BlackAntDockerError(f"Tag retrieval failed: {error}") from error

    def get_manifest(self, repository: str, tag: str) -> Dict[str, Any]:
        """Get image manifest.

        Args:
            repository: Repository name.
            tag: Image tag.

        Returns:
            Image manifest data.

        Raises:
            BlackAntDockerError: If manifest retrieval fails.
        """
        try:
            # Request with proper Accept header for manifest v2
            response = self.http_client.send_request(
                endpoint=f"/v2/{repository}/manifests/{tag}",
                method="GET"
            )

            # Add Accept header manually if needed
            if hasattr(response, 'request'):
                response.request.headers['Accept'] = (
                    'application/vnd.docker.distribution.manifest.v2+json, '
                    'application/vnd.docker.distribution.manifest.v1+json'
                )

            response.raise_for_status()

            manifest = response.json()
            self.logger.debug(f"Retrieved manifest for {repository}:{tag}")
            return manifest

        except HTTPConnectionError as error:
            self.logger.error(f"Failed to get manifest: {error}")
            raise BlackAntDockerError(f"Could not get manifest: {error}") from error
        except Exception as error:
            self.logger.error(f"Unexpected error getting manifest: {error}")
            raise BlackAntDockerError(f"Manifest retrieval failed: {error}") from error

    def check_health(self) -> bool:
        """Check registry health.

        Returns:
            True if registry is healthy.

        Raises:
            BlackAntDockerError: If health check fails.
        """
        try:
            response = self.http_client.send_request(
                endpoint="/v2/",
                method="GET"
            )

            # Registry should return 200 for /v2/ endpoint
            return response.status_code == 200

        except Exception:
            return False
