# Copyright © The Debusine Developers
# See the AUTHORS file at the top-level directory of this distribution
#
# This file is part of Debusine. It is subject to the license terms
# in the LICENSE file found in the top-level directory of this
# distribution. No part of Debusine, including this file, may be copied,
# modified, propagated, or distributed except according to the terms
# contained in the LICENSE file.

"""UI helpers for scopes."""

from functools import cached_property
from typing import Any

from django.core.exceptions import ImproperlyConfigured
from django.urls import reverse
from django.utils.html import format_html

from debusine.db.context import context
from debusine.db.models import Scope
from debusine.web.icons import Icons
from debusine.web.views.places import (
    ContainerPlace,
    ResourcePlace,
    ResourcePlaceKwargs,
)
from debusine.web.views.ui.base import UI


class ScopePlace(ResourcePlace):
    """
    Place with a custom URL.

    This subclass tweaks rendering to use images from static files instead of
    bootstrap icons.
    """

    def as_icon(self, **kwargs: Any) -> str:
        """
        Render the icon.

        :returns: the rendered HTML, or an empty string if this Place has no
          icon
        """
        from django.contrib.staticfiles.storage import staticfiles_storage

        url = staticfiles_storage.url(self.icon)
        return format_html(
            """<img src="{url}" style="height: 1em;" """
            """ class="d-inline-block align-middle"> """,
            url=url,
        )


class ScopeUI(UI[Scope]):
    """UI helpers for Scope instances."""

    @cached_property
    def place(self) -> ResourcePlace:
        """Return a place to show this scope."""
        from debusine.server.scopes import urlconf_scope

        with urlconf_scope(self.instance.name):
            url = reverse(
                "scopes:detail",
            )

        kwargs: ResourcePlaceKwargs = {
            "title": self.instance.name,
            "breadcrumb": self.instance.name,
            "url": url,
            "icon": Icons.SCOPE,
            "description": f"{self.instance.name} scope",
        }

        # Scope has an icon attribute which may be set to the appropriate
        # logo. If set, use a custom place implementation so we generate icons
        # as <img> tags instead of <span> ones
        if self.instance.icon:
            kwargs["icon"] = self.instance.icon
            return ScopePlace(**kwargs)
        else:
            return ResourcePlace(**kwargs)

    @cached_property
    def place_group_list(self) -> ContainerPlace:
        """Return a place for the current user group in this scope."""
        from debusine.server.scopes import urlconf_scope

        user = context.user
        if user is None or not user.is_authenticated:
            raise ImproperlyConfigured(
                "ScopeUI.place_group_list invoked without a current user"
            )

        with urlconf_scope(self.instance.name):
            url = reverse(
                "user:groups",
                kwargs={"username": user.username},
            )

        return ContainerPlace(
            title=f"Group list for {user} in scope {context.scope}",
            breadcrumb="groups",
            url=url,
            description=f"Groups in scope {self.instance.name}"
            f" accessible by {context.user}",
            parent=self.instance.ui(self.request).place,
        )
