#!/usr/bin/env python
"""
Manage project badges on GitLab.
"""

import logging
import tomllib

from ...python.common import get_pypi_url

LOGGER = logging.getLogger(__name__)


def get_badge_url(label, message, color):
    """
    Get a URL to an SVG image of a custom badge generated by the img.shields.io
    website.

    Args:
        label:
            The text on the left side of the badge.

        message:
            The text on the right side of the badge.

        color:
            The hexadecimal color code for the background of the message.

    Returns:
        The image URL as a string.
    """
    for char, escape in (("_", "__"), (" ", "_"), ("-", "--")):
        label = label.replace(char, escape)
        message = message.replace(char, escape)
    return f"https://img.shields.io/badge/{label}-{message}-{color}.svg"


class GitLabBadgesMixin:
    """
    Mixin to handle badges in GitLabApi class.
    """

    def manage_badges(self):
        """
        Add or remove badges depending on the current repository configuration.
        """
        self.manage_license_badge()
        self.manage_pipeline_badge()
        self.manage_python_badges()

    def is_enabled(self, name):
        """
        Check if a given badge is enabled, i.e. configured to be handled by this
        class.
        """
        LOGGER.debug("Check if badge is enabled: %s", name)
        enabled = self.project.config.get("gitlab", "enabled_badges")
        is_enabled = enabled and name in enabled
        if is_enabled:
            LOGGER.debug("Managing badge: %s", name)
        return is_enabled

    def get_badge_by_name(self, name):
        """
        Get a badge by name.

        Args:
            name:
                The name of the badge.

        Returns:
            The Badge instance, or None of not badge of the given name was
            found.
        """
        for badge in self.gitlab_project.badges.list(get_all=True):
            if badge.name == name:
                return badge
        return None

    def create_badge(self, name, link_url, image_url):
        """
        Create a new badge.

        Args:
            name:
                The badge name.

            link_url:
                The badge link URL.

            image_url:
                The badge image URL.
        """
        LOGGER.info("Creating badge: %s", name)
        self.gitlab_project.badges.create(
            {"name": name, "link_url": link_url, "image_url": image_url}
        )

    @staticmethod
    def update_badge(badge, link_url, image_url):
        """
        Update a badge if necessary.

        Args:
            badge:
                A Badge instance.

            link_url:
                The badge link URL.

            image_url:
                The badge image URL.
        """
        if badge.link_url != link_url or badge.image_url != image_url:
            LOGGER.info("Updating badge: %s", badge.name)
            badge.link_url = link_url
            badge.image_url = image_url
            badge.save()

    @staticmethod
    def delete_badge(badge):
        """
        Delete a badge.

        Args:
            badge:
                A Badge instance.
        """
        LOGGER.info("Deleting badge: %s", badge.name)
        badge.delete()

    def manage_pipeline_badge(self):
        """
        Manage the pipeline status badge.
        """
        name = "Pipeline Status"
        if not self.is_enabled(name):
            return
        host, _namespace, _name = self.project.git_repo.parsed_origin
        protocol = "https"
        link_url = (
            f"{protocol}://{host}/%{{project_path}}/-/commits/%{{default_branch}}"
        )
        image_url = f"{protocol}://{host}/%{{project_path}}/badges/%{{default_branch}}/pipeline.svg"
        badge = self.get_badge_by_name(name)
        if self.project.git_host.gitlab_ci.path.exists():
            if badge is None:
                self.create_badge(name, link_url, image_url)
            else:
                self.update_badge(badge, link_url, image_url)
        else:
            if badge is not None:
                self.delete_badge(badge)

    def manage_license_badge(self):
        """
        Manage the license badge.
        """
        name = "License"
        if not self.is_enabled(name):
            return
        lic = self.project.spdx_license
        badge = self.get_badge_by_name(name)
        if lic is None:
            if badge is not None:
                self.delete_badge(badge)
        else:
            link_url = f"https://spdx.org/licenses/{lic}.html"
            image_url = get_badge_url("license", lic, "9400d3")
            if badge is None:
                self.create_badge(name, link_url, image_url)
            else:
                self.update_badge(badge, link_url, image_url)

    def manage_python_badges(self):
        """
        Manage Python badges.
        """
        package = self.project.packages.get("python")
        if not package:
            return
        self._manage_pypi_badge(package)
        self._manage_pypi_downloads_badge(package)
        self._manage_hatch_badge(package)

    def _manage_pypi_badge(self, package):
        """
        Manage PyPI badge.
        """
        name = "PyPI"
        if not self.is_enabled(name):
            return
        badge = self.get_badge_by_name(name)
        pypi_name = package.name
        link_url = package.pypi_url
        if link_url:
            image_url = get_badge_url("PyPI", pypi_name, "006dad")
            if badge is None:
                self.create_badge(name, link_url, image_url)
            else:
                self.update_badge(badge, link_url, image_url)
            return
        self.delete_badge(name)

    def _manage_pypi_downloads_badge(self, package):
        """
        Manage the PyPI downloads badge.
        """
        name = "PyPI Downloads"
        if not self.is_enabled(name):
            return
        badge = self.get_badge_by_name(name)
        pypi_name = package.name
        pypi_url = package.pypi_url
        if pypi_url:
            link_url = f"https://pepy.tech/projects/{pypi_name}"
            image_url = f"https://static.pepy.tech/badge/{pypi_name}"
            if badge is None:
                self.create_badge(name, link_url, image_url)
            else:
                self.update_badge(badge, link_url, image_url)
            return
        self.delete_badge(name)

    def _manage_hatch_badge(self, package):
        """
        Manage the Python Hatch badge.
        """
        name = "Hatch"
        if not self.is_enabled(name):
            return
        badge = self.get_badge_by_name(name)
        backend = package.pyproject_toml_data.get("build-system", {}).get(
            "build-backend"
        )

        if backend == "hatchling.build":
            link_url = "https://github.com/pypa/hatch"
            image_url = get_badge_url("%F0%9F%A5%9A", "Hatch", "4051b5")
            if badge is None:
                self.create_badge(name, link_url, image_url)
            else:
                self.update_badge(badge, link_url, image_url)
            return
        self.delete_badge(name)
