# 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 for QA work request."""

from functools import cached_property
from typing import Any, override

from debusine.artifacts.models import TaskTypes
from debusine.db.models import Artifact
from debusine.db.tasks import DBTask
from debusine.server.workflows import QAWorkflow
from debusine.tasks.models import RegressionAnalysisStatus
from debusine.web.views.work_request import Tab, WorkRequestPlugin


class QATab(Tab):
    """QA specialized tab."""

    def __init__(self, task: QAWorkflow) -> None:
        """Define this tab."""
        super().__init__(name="qa", label="QA")
        self.task = task
        self.work_request = task.work_request

    @cached_property
    def has_data(self) -> bool:
        """Check if the tab has data to display."""
        return (
            self.work_request.output_data is not None
            and self.work_request.output_data.regression_analysis is not None
            and "" in self.work_request.output_data.regression_analysis
        )

    @override
    def get_context_data(self) -> dict[str, Any]:
        # Assert the invariants that are checked by has_data
        assert self.work_request.output_data is not None
        regression_analysis = self.work_request.output_data.regression_analysis
        assert regression_analysis is not None
        summary = regression_analysis.get("")
        assert summary is not None

        # Prefetch referenced artifacts
        ids: set[int] = set()
        for analysis in regression_analysis.values():
            if analysis.original_artifact_id is not None:
                ids.add(analysis.original_artifact_id)
            if analysis.new_artifact_id is not None:
                ids.add(analysis.new_artifact_id)
        artifacts: dict[int, Artifact] = {}
        for artifact in Artifact.objects.filter(id__in=ids).select_related(
            "created_by_work_request"
        ):
            artifacts[artifact.pk] = artifact

        def get_artifact(pk: int | None) -> Artifact | None:
            if pk is None:
                return None
            return artifacts.get(pk)

        # TODO: is there a better way to get the package name?
        assert self.task.dynamic_data is not None
        assert self.task.dynamic_data.subject is not None
        package_name: str = self.task.dynamic_data.subject

        rows: list[dict[str, Any]] = []
        warnings: list[str] = []

        task = self.task
        assert isinstance(task, QAWorkflow)

        for name, analysis in sorted(regression_analysis.items()):
            if name == "":
                continue
            task_name, test_package_name, _ = name.split(":")
            if (
                task_name == "autopkgtest"
                and test_package_name != package_name
                and analysis.status
                in (
                    RegressionAnalysisStatus.NO_RESULT,
                    RegressionAnalysisStatus.STABLE,
                )
            ):
                # Hide NO_RESULT and STABLE reverse dependency autopkgtest
                # results to avoid cluttering the UI
                continue

            rows.append(
                {
                    "name": name,
                    "orig": get_artifact(analysis.original_artifact_id),
                    "new": get_artifact(analysis.new_artifact_id),
                    "analysis": analysis,
                }
            )

        return {
            "summary": summary,
            "orig": get_artifact(summary.original_artifact_id),
            "new": get_artifact(summary.new_artifact_id),
            "rows": rows,
            "warnings": warnings,
        }


class QAViewWorkRequestPlugin(WorkRequestPlugin):
    """View for QA work request."""

    task_type = TaskTypes.WORKFLOW
    task_name = "qa"
    task: QAWorkflow

    def __init__(self, task: DBTask[Any]) -> None:
        """Instantiate the tab."""
        super().__init__(task)
        self.tab = QATab(self.task)

    @override
    def is_enabled(self) -> bool:
        return self.tab.has_data

    @override
    def add_tabs(self, tabs: list[Tab]) -> None:
        tabs.insert(0, self.tab)

    @override
    def get_context_data(self) -> dict[str, Any]:
        return {}
