# 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, override

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

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


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

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

    @override
    def as_icon(self, **kwargs: Any) -> str:
        from django.contrib.staticfiles.storage import staticfiles_storage

        # If the place does not want an icon, do not generate one
        if self.icon is None:
            return SafeString()

        if not (icon := self.ui.instance.icon):
            return super().as_icon(**kwargs)

        # Scope has an icon attribute which may be set to the appropriate
        # logo. If set, generate icons as <img> tags instead of using Bootstrap
        # icons
        return format_html(
            """<img src="{url}" style="height: 1em;" """
            """ class="d-inline-block align-middle"> """,
            url=staticfiles_storage.url(icon),
        )


class ScopeMainPlace(ScopePlace, ResourceMainPlace[Scope]):
    """Main place for showing a Scope."""


class ScopeSubPlace(ScopePlace, ResourceSubPlace[Scope]):
    """Place for working with a resource."""


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

    @cached_property
    def place(self) -> ScopeMainPlace:
        """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[Scope] = {
            "ui": self,
            "title": PlaceValue(
                self.instance.name, page=f"{self.instance.name} scope"
            ),
            "url": url,
            "icon": Icons.SCOPE,
            "description": f"{self.instance.name} scope",
        }

        return ScopeMainPlace(**kwargs)

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

        if not (user := self.request.user).is_authenticated:
            raise ImproperlyConfigured(
                "ScopeUI.place_group_list invoked by an anonymous user"
            )

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

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