"""
Alliance Auth integration hooks.

Two hooks register here:

- ``DiscordAuditMenu``: sidebar menu entry under AA's main nav,
  rendered only for users holding ``view_auditrun``. The icon /
  order match AA's other audit-style plugins (Permissions Audit
  uses fa-id-card at order 400; we sit one slot below).
- ``register_url``: mounts ``urls.py`` under ``audit/discord/`` so
  AA's plugin-aware URL conf includes the views without a project-
  level urls edit.

AA wraps every plugin URL with ``main_character_required`` at
include time; this is the standard plugin contract and tests must
seed users via ``AuthUtils.create_member`` + ``add_main_character``
to reach the views.
"""

from __future__ import annotations

from typing import TYPE_CHECKING

from allianceauth import hooks
from allianceauth.menu.hooks import MenuItemHook
from allianceauth.services.hooks import UrlHook

from . import urls
from .permissions import APP_LABEL, VIEW_AUDITRUN

if TYPE_CHECKING:
    from django.http import HttpRequest


class DiscordAuditMenu(MenuItemHook):
    """Sidebar menu entry; gated on ``view_auditrun``."""

    def __init__(self) -> None:
        """Configure the menu label, icon, and reverse target."""
        super().__init__(
            "Discord Audit",
            "fa-solid fa-shield-halved",
            f"{APP_LABEL}:run_list",
            order=410,
            navactive=[f"{APP_LABEL}:"],
        )

    def render(self, request: HttpRequest) -> str:
        """Hide the menu link from users without the view perm."""
        # ``request.user`` is typed as ``AbstractBaseUser | AnonymousUser``
        # by django-stubs; ``has_perm`` exists on every user class
        # AA actually wires up (``AnonymousUser`` always returns
        # ``False``, configured user models inherit ``PermissionsMixin``).
        if request.user.has_perm(VIEW_AUDITRUN):  # type: ignore[union-attr]
            return str(super().render(request))
        return ""


# ``hooks.register`` is typed by allianceauth-stubs as
# ``Callable[..., Any] | None`` — pyright correctly flags the
# decorator-call as possibly-None. Runtime never returns None;
# the stub gap is documented upstream.
@hooks.register("menu_item_hook")  # pyright: ignore[reportOptionalCall]
def register_menu() -> DiscordAuditMenu:
    """Expose the sidebar menu item to AA's hook framework."""
    return DiscordAuditMenu()


@hooks.register("url_hook")  # pyright: ignore[reportOptionalCall]
def register_url() -> UrlHook:
    """Mount ``urls.py`` under ``audit/discord/`` via AA's URL hook."""
    return UrlHook(urls, APP_LABEL, r"^audit/discord/")
