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

"""Pydantic models used by debusine workflows."""

from typing import Any

try:
    import pydantic.v1 as pydantic
except ImportError:
    import pydantic as pydantic  # type: ignore

from debusine.tasks.models import BackendType, BaseTaskData, SbuildInput


class BaseWorkflowData(BaseTaskData):
    """
    Base class for workflow data.

    Workflow data is encoded as JSON in the database, and it is modeled as a
    pydantic data structure in memory for both ease of access and validation.
    """


class WorkRequestWorkflowData(pydantic.BaseModel):
    """Data structure for WorkRequest.workflow_data."""

    class Config:
        """Set up stricter pydantic Config."""

        validate_assignment = True
        extra = pydantic.Extra.forbid

    #: If the work request fails, if True the workflow can continue, if false
    #: it is interrupted
    allow_failure: bool = pydantic.Field(default=False, allow_mutation=False)

    #: name of the step in the visual representation of the workflow
    display_name: str = pydantic.Field(allow_mutation=False)

    #: internal identifier used to differentiate multiple workflow callbacks
    #: inside a single workflow. It allows the orchestrator to encode the plan
    #: about what it is supposed to do at this point in the workflow.
    step: str = pydantic.Field(allow_mutation=False)

    #: Name of the group within this workflow containing this work request.
    group: str | None = pydantic.Field(default=None, allow_mutation=False)


class SbuildWorkflowData(BaseWorkflowData):
    """Sbuild workflow data."""

    input: SbuildInput
    target_distribution: str
    # If AUTO is used, default to BackendType.UNSHARE
    backend: BackendType = BackendType.AUTO
    architectures: list[str] = pydantic.Field(
        min_items=1,
        unique_items=True,
    )
    environment_variant: str | None = None


class UpdateEnvironmentsWorkflowTarget(BaseWorkflowData):
    """A target for an update_environments workflow."""

    codenames: str | list[str]
    codename_aliases: dict[str, list[str]] = pydantic.Field(
        default_factory=dict
    )
    variants: str | list[str] = pydantic.Field(default_factory=list)
    backends: str | list[str] = pydantic.Field(default_factory=list)
    architectures: list[str] = pydantic.Field(min_items=1, unique_items=True)
    mmdebstrap_template: dict[str, Any] | None = None
    simplesystemimagebuild_template: dict[str, Any] | None = None


class UpdateEnvironmentsWorkflowData(BaseWorkflowData):
    """update_environments workflow data."""

    vendor: str
    targets: list[UpdateEnvironmentsWorkflowTarget] = pydantic.Field(
        min_items=1
    )
