"""
Artifact provider for creating DNF repositories from baseurl.
"""

from collections.abc import Sequence
from functools import cached_property
from re import Pattern
from typing import Optional

import tmt.log
import tmt.utils
from tmt.guest import Guest
from tmt.steps.prepare.artifact.providers import (
    ArtifactInfo,
    ArtifactProvider,
    ArtifactProviderId,
    Repository,
    UnsupportedOperationError,
    provides_artifact_provider,
)
from tmt.steps.prepare.artifact.providers.repository import _REPO_NAME_GENERATOR


@provides_artifact_provider('repository-url')
class RepositoryUrlProvider(ArtifactProvider):
    """
    Provider for making RPM artifacts from a repository discoverable without downloading them.

    The provider identifier should start with 'repository-url:' followed by a baseurl
    to a DNF repository, e.g., "repository-url:https://example.com/repo/".

    The provider generates a .repo file with the given baseurl, which will be installed to the
    guest's ``/etc/yum.repos.d/`` directory, and lists RPMs available in the repository
    without downloading them, acting as a discovery-only provider. Artifacts are all available
    RPM packages listed in the repository.

    :param raw_provider_id: The full provider identifier, starting with 'repository-url:'.
    :param logger: Logger instance for outputting messages.
    :raises ValueError: If the provider identifier format is invalid or the baseurl is missing.
    """

    # FIXME: This docstring will need refactoring when the documentation of PrepareArtifact
    #        is made dynamic.

    repository: Repository

    def __init__(self, raw_provider_id: str, repository_priority: int, logger: tmt.log.Logger):
        super().__init__(raw_provider_id, repository_priority, logger)

    @classmethod
    def _extract_provider_id(cls, raw_provider_id: str) -> ArtifactProviderId:
        prefix = 'repository-url:'
        if not raw_provider_id.startswith(prefix):
            raise ValueError(f"Invalid repository-url provider format: '{raw_provider_id}'.")
        value = raw_provider_id[len(prefix) :]
        if not value:
            raise ValueError("Missing repository baseurl.")
        return value

    @cached_property
    def artifacts(self) -> Sequence[ArtifactInfo]:
        # Repository provider does not enumerate individual artifacts.
        # The repository is installed and packages are available through the package manager.
        # There is no need to download individual artifact files.
        return []

    def _download_artifact(
        self, artifact: ArtifactInfo, guest: Guest, destination: tmt.utils.Path
    ) -> None:
        """This provider only discovers repos; it does not download individual RPMs."""
        raise UnsupportedOperationError(
            "RepositoryUrlProvider does not support downloading individual RPMs."
        )

    def fetch_contents(
        self,
        guest: Guest,
        download_path: tmt.utils.Path,
        exclude_patterns: Optional[list[Pattern[str]]] = None,
    ) -> list[tmt.utils.Path]:
        # Fetches and initializes the repository from the baseurl.
        # Repository provider does not download individual artifacts. Instead, it creates
        # a .repo file which will be installed via get_repositories(). Packages are
        # then available through the package manager.
        # It returns an empty list, as no individual artifact files are downloaded.

        baseurl = self.id
        repo_name = f"tmt-repo-{_REPO_NAME_GENERATOR.get()}"

        self.logger.info(f"Setting up repository from baseurl: {baseurl} (name: {repo_name})")

        # Generate .repo file content
        repo_content = f"""[{tmt.utils.sanitize_name(repo_name)}]
name={repo_name}
baseurl={baseurl}
enabled=1
gpgcheck=0
priority={self.repository_priority}"""

        self.logger.debug(f"Generated .repo file content:\n{repo_content}")

        # Create Repository object
        self.repository = Repository.from_content(
            content=repo_content, name=repo_name, logger=self.logger
        )

        self.logger.info(f"Repository initialized: {self.repository.name} (baseurl: {baseurl})")
        return []

    def get_repositories(self) -> list[Repository]:
        self.logger.info(f"Providing repository '{self.repository.name}' for installation")
        return [self.repository]
