# 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.

"""
View extension to model sidebar elements.

Sidebar elements are informational elements or actions that can be used to
populate the UI sidebar.
"""

import datetime as dt
from dataclasses import dataclass
from functools import cached_property
from typing import override

from django.db.models import Model
from django.template.context import BaseContext
from django.utils.formats import date_format
from django.utils.html import format_html
from django.utils.safestring import SafeString
from django.utils.timesince import timesince

from debusine.db.models import Artifact, User, WorkRequest, Worker, Workspace
from debusine.web.icons import Icons
from debusine.web.views.base import Widget


@dataclass(kw_only=True, frozen=True)
class SidebarItem(Widget):
    """Renderable element for the right sidebar."""

    #: icon to use
    icon: str = "app"
    #: label describing what the field is about
    label: str
    #: user-presented value for the field
    value: str | None = None
    #: detailed information about the value
    detail: str | None = None

    @cached_property
    def content(self) -> str:
        """Select the main content to display."""
        if self.value:
            return self.value
        if self.detail:
            return self.detail
        return "-"

    @cached_property
    def main_tooltip(self) -> str:
        """Select what to use as tooltip for the whole entry."""
        if self.detail and self.value and self.detail != self.value:
            return self.detail
        return self.label

    @cached_property
    def icon_tooltip(self) -> str | None:
        """Select if a tooltip is shown on the icon, and what it is."""
        if self.main_tooltip == self.label:
            return None
        return self.label

    @override
    def render(self, context: BaseContext) -> str:
        raise NotImplementedError(
            f"{self.__class__.__name__}.render not implemented"
        )


@dataclass(kw_only=True, frozen=True)
class SidebarElement(SidebarItem):
    """Informative element for the right sidebar."""

    @override
    def render(self, context: BaseContext) -> str:  # noqa: ARG002, U100
        if self.icon_tooltip:
            icon_title = format_html(' title="{}"', self.icon_tooltip)
        else:
            icon_title = SafeString()
        return format_html(
            '<span class="list-group-item" title="{main_tooltip}">'
            '<span class="bi bi-{icon}"{icon_title}></span> '
            '{content}</span>',
            main_tooltip=self.main_tooltip,
            icon_title=icon_title,
            icon=self.icon,
            content=self.content,
        )


@dataclass(kw_only=True, frozen=True)
class SidebarAction(SidebarItem):
    """Action element for the right sidebar."""

    # Action URL
    url: str

    @override
    def render(self, context: BaseContext) -> str:  # noqa: ARG002, U100
        if self.icon_tooltip:
            icon_title = format_html(' title="{}"', self.icon_tooltip)
        else:
            icon_title = SafeString()
        return format_html(
            '<a class="list-group-item list-group-item-action'
            ' d-flex justify-content-between"'
            ' title="{main_tooltip}" href="{url}">'
            '<span><span class="bi bi-{icon}"{icon_title}></span> '
            '{content}</span>'
            '<span>…</span>'
            '</a>',
            main_tooltip=self.main_tooltip,
            icon_title=icon_title,
            url=self.url,
            icon=self.icon,
            content=self.content,
        )


def create_workspace(workspace: Workspace) -> SidebarItem:
    """Create workspace information."""
    return SidebarAction(
        url=workspace.get_absolute_url(),
        icon="person-workspace",
        label="Workspace",
        value=workspace.name,
    )


def create_user(
    user: User | None, *, context: Model | None = None
) -> SidebarItem:
    """Create user information."""
    match context:
        case WorkRequest():
            title = "User who created the work request"
        case Artifact():
            title = "User who created the artifact"
        case _:
            title = "User"

    return SidebarElement(
        icon=Icons.USER,
        label=title,
        value=str(user) if user else None,
    )


def create_created_at(at: dt.datetime) -> SidebarItem:
    """Create created_at information."""
    return SidebarElement(
        icon=Icons.CREATED_AT,
        label="Created",
        value=timesince(at) + " ago",
        detail=date_format(at, "DATETIME_FORMAT"),
    )


def create_expire_at(at: dt.datetime | None) -> SidebarItem:
    """Create expire_at information."""
    kwargs = {
        "icon": Icons.EXPIRE_AT,
        "label": "Expiration date",
    }
    if at:
        return SidebarElement(
            detail=date_format(at, "DATETIME_FORMAT"),
            value=timesince(at, reversed=True),
            **kwargs,
        )
    else:
        return SidebarElement(value="Never", **kwargs)


def create_worker(worker: Worker | None) -> SidebarItem:
    """Create a link to a worker."""
    kwargs = {
        "icon": Icons.WORKER,
        "label": "Worker",
    }
    if worker is None:
        return SidebarElement(**kwargs)
    return SidebarAction(
        value=worker.name, url=worker.get_absolute_url(), **kwargs
    )
