# 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 work requests."""

from collections import defaultdict
from functools import cached_property

from debusine.artifacts.models import TaskTypes
from debusine.db.models import WorkRequest, WorkflowTemplate
from debusine.web.helps import DOCS_BASE_URL
from debusine.web.icons import Icons
from debusine.web.views.places import ResourcePlace
from debusine.web.views.ui.base import UI


class WorkflowTemplateUI(UI[WorkflowTemplate]):
    """UI helpers for WorkflowTemplate instances."""

    @cached_property
    def place(self) -> ResourcePlace:
        """Return a place to show this workflow template."""
        return ResourcePlace(
            title=f"Workflow template {self.instance.name}",
            url=self.instance.get_absolute_url(),
            breadcrumb=self.instance.name,
            parent=self.instance.workspace.ui(self.request).place,
        )

    def get_help_url(self) -> str:
        """Return a URL to the appropriate workflow documentation."""
        # We could avoid hardcoding this URL structure by using Sphinx to
        # fetch and parse the intersphinx inventory.  However, Sphinx seems
        # like too heavy a dependency to pull in just for this.
        return (
            f"{DOCS_BASE_URL}/reference/workflows/specs/"
            f"{self.instance.task_name.replace('_', '-')}.html"
        )


class WorkRequestUI(UI[WorkRequest]):
    """UI helpers for WorkRequest instances."""

    @cached_property
    def place(self) -> ResourcePlace:
        """Return a place to show this work request."""
        is_workflow_root = self.instance == self.instance.workflow_root
        place = ResourcePlace(
            title=f"#{self.instance.id}: {self.instance.get_label()}",
            description=f"Work request #{self.instance.id}:"
            f" {self.instance.get_label()}",
            breadcrumb=(
                f"#{self.instance.id}: {self.instance.get_label()}"
                if is_workflow_root
                else f"#{self.instance.id}"
            ),
            url=self.instance.get_absolute_url(),
            icon=Icons.WORK_REQUEST,
        )
        if self.instance.parent is not None:
            place.parent = self.instance.parent.ui(self.request).place
        elif self.instance.task_type == TaskTypes.WORKFLOW:
            place.parent = self.instance.workspace.ui(
                self.request
            ).place_workflow_list
        else:
            place.parent = self.instance.workspace.ui(self.request).place
        return place

    @cached_property
    def workflow_children(self) -> dict[int, list[WorkRequest]]:
        """Mapping from work request IDs to their children in this workflow."""
        children: defaultdict[int, list[WorkRequest]] = defaultdict(list)
        for wr in (
            WorkRequest.objects.filter(id=self.instance.id)
            .workflow_flattened(include_workflows=True)
            .filter(parent__isnull=False)
            .visible_in_workflow()
            .order_by("id")
            .select_related(
                "workspace__scope",
                "aborted_by",
            )
        ):
            assert wr.parent_id is not None
            children[wr.parent_id].append(wr)
        return children
