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

"""Models used by debusine server-side tasks."""

import datetime as dt
import re
from typing import Annotated, Any, Self, override

import pydantic

from debusine.artifacts.models import WorkRequestResults
from debusine.db.models.workspaces import workspace_name_regex
from debusine.tasks.models import (
    BaseDynamicTaskData,
    BaseTaskData,
    LookupMultiple,
    LookupSingle,
)


class ServerNoopData(BaseTaskData):
    """In-memory task data for the ServerNoop task."""

    exception: bool = False
    result: WorkRequestResults = WorkRequestResults.FAILURE


class APTMirrorFilter(BaseTaskData):
    """A filter for APT repository mirroring."""

    binary_name: re.Pattern[str] | None = None
    priority: str | None = None
    section: str | None = None
    source_name: re.Pattern[str] | None = None

    ignore_unauthorized: bool = False


class APTMirrorData(BaseTaskData):
    """In-memory task data for the APTMirror task."""

    collection: str
    url: pydantic.AnyUrl
    suite: str
    components: list[str] | None = None
    architectures: list[str] | None = None
    signing_key: str | None = None
    filters: list[APTMirrorFilter] | None = None
    authentication: str | None = None

    @pydantic.model_validator(mode="after")
    def check_suite_components_consistency(self) -> Self:
        """Components are only allowed/required for non-flat repositories."""
        if self.suite.endswith("/"):
            if self.components is not None:
                raise ValueError(
                    'Flat repositories (where suite ends with "/") must not '
                    'have components'
                )
        else:
            if self.components is None:
                raise ValueError(
                    'Non-flat repositories (where suite does not end with '
                    '"/") must have components'
                )
        return self


class PackageUploadInput(BaseTaskData):
    """Input for the PackageUpload task."""

    upload: LookupSingle


class PackageUploadTarget(pydantic.AnyUrl):
    """
    Target URL for the PackageUpload task.

    While this may contain a user and password, note that these are not
    currently secret.
    """

    allowed_schemes = {"ftp", "sftp"}


class PackageUploadData(BaseTaskData):
    """In-memory task data for the PackageUpload task."""

    input: PackageUploadInput
    target: PackageUploadTarget
    delayed_days: int | None = None


class PackageUploadDynamicData(BaseDynamicTaskData):
    """Dynamic data for the PackageUpload task."""

    input_upload_id: int

    @override
    def get_input_artifacts_ids(self) -> list[int]:
        return [self.input_upload_id]


class CopyCollectionItemsCopies(BaseTaskData):
    """Specification of a set of copies for the CopyCollectionItems task."""

    source_items: LookupMultiple
    target_collection: LookupSingle
    unembargo: bool = False
    replace: bool = False
    name_template: str | None = None
    variables: dict[str, Any] | None = None


class CopyCollectionItemsData(BaseTaskData):
    """In-memory task data for the CopyCollectionItems task."""

    copies: Annotated[
        list[CopyCollectionItemsCopies], pydantic.Field(min_length=1)
    ]


class CreateChildWorkspaceData(BaseTaskData):
    """In-memory task data for CreateChildWorkspace."""

    prefix: Annotated[str, pydantic.Field(pattern=workspace_name_regex)]
    suffix: Annotated[str, pydantic.Field(pattern=workspace_name_regex)]
    public: bool = True
    owner_group: str | None = None
    workflow_template_names: list[str] = []
    expiration_delay: int | None = 60


class GenerateSuiteIndexesData(BaseTaskData):
    """In-memory task data for GenerateSuiteIndexes."""

    suite_collection: LookupSingle
    generate_at: dt.datetime


class GenerateSuiteIndexesDynamicData(BaseDynamicTaskData):
    """Dynamic data for the GenerateSuiteIndexes task."""

    suite_collection_id: int
