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

"""Wait task to ask a user for confirmation."""

from typing import TYPE_CHECKING, assert_never

from debusine.server.tasks.wait import BaseWaitTask
from debusine.server.tasks.wait.models import ConfirmData, DenyAction
from debusine.tasks import DefaultDynamicData
from debusine.tasks.models import BaseDynamicTaskData, Confirmation, OutputData

if TYPE_CHECKING:
    from debusine.db.models import User


class Confirm(
    BaseWaitTask[ConfirmData, BaseDynamicTaskData],
    DefaultDynamicData[ConfirmData],
):
    """Task that waits for user confirmation."""

    TASK_VERSION = 1

    def _execute(self) -> bool:
        """Never called; the scheduler completes these tasks directly."""
        raise NotImplementedError()

    def get_label(self) -> str:
        """Return the task label."""
        return "wait for confirmation"

    def respond(
        self, *, user: "User", confirm: bool, comment: str | None = None
    ) -> None:
        """
        Process a response from the user.

        This is called on the server, either from the API or the web UI.
        """
        from debusine.db.models import WorkRequest

        assert self.work_request is not None

        output_data = OutputData(
            confirmation=Confirmation(confirmed=confirm, comment=comment)
        )
        if confirm:
            self.work_request.mark_completed(
                WorkRequest.Results.SUCCESS, user=user, output_data=output_data
            )
        else:
            match self.data.deny_action:
                case DenyAction.FAIL:
                    self.work_request.mark_completed(
                        WorkRequest.Results.FAILURE,
                        user=user,
                        output_data=output_data,
                    )
                case DenyAction.ABORT:
                    self.work_request.abort(output_data=output_data)
                case DenyAction.ABORT_WORKFLOW:
                    # If this isn't part of a workflow, just abort the work
                    # request itself.  This is easier than trying to
                    # validate that this deny_action can only be used in
                    # work requests that are part of a workflow, and it
                    # should be close enough to what the user intended.
                    (
                        self.work_request.workflow_root or self.work_request
                    ).abort(output_data=output_data)
                case _ as unreachable:
                    assert_never(unreachable)
