# Copyright © The Debusine Developers     ■ /home/enrico/lavori/freexian/debusine/pyproject.toml:1:1:1:1: error: Error importing plugin "mypy_django_plugin.main": No module named 'mypy_django_plugin'  [misc]
# 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.

"""Add missing archive constraints from suite constraints."""

import logging
from typing import Any

from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps

from debusine.artifacts.models import CollectionCategory

logger = logging.getLogger(__name__)


def add_missing_archive_constraints(
    apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
) -> None:
    """
    Regenerate archive constraints from suite constraints.

    This is intended to compensate for archive constraints not having been
    added in past versions of Debusine
    """
    Workspace = apps.get_model("db", "Workspace")
    Collection = apps.get_model("db", "Collection")
    CollectionItemMatchConstraint = apps.get_model(
        "db", "CollectionItemMatchConstraint"
    )

    def process_workspace(workspace: Any, constraint_name: str) -> None:
        assert isinstance(workspace, Workspace)
        try:
            archive = workspace.collections.get(
                name="_", category=CollectionCategory.ARCHIVE
            )
        except Collection.DoesNotExist:
            # Skip workspaces with no archives
            return

        # Collect existing suite-level constraints
        suite_constraints: dict[str, tuple[int, str]] = {}
        for c in CollectionItemMatchConstraint.objects.filter(
            collection__workspace=workspace,
            collection__category=CollectionCategory.SUITE,
            constraint_name=constraint_name,
        ).order_by("id"):
            if c.key in suite_constraints:
                logging.warning(
                    "%s: %s: same file found in different suites"
                    " with different contents:"
                    " manual intervention is needed to fix the inconsistency",
                    workspace,
                    c.key,
                )
            # In case of conflict arbitrarily create the archive constraint
            # using the constraint entry with the highest ID
            suite_constraints[c.key] = (c.collection_item_id, c.value)

        # Delete and recreate archive constraints
        CollectionItemMatchConstraint.objects.filter(
            collection__workspace=workspace,
            collection__category=CollectionCategory.ARCHIVE,
            constraint_name=constraint_name,
        ).delete()
        CollectionItemMatchConstraint.objects.bulk_create(
            (
                CollectionItemMatchConstraint(
                    collection=archive,
                    collection_item_id=item_id,
                    constraint_name=constraint_name,
                    key=key,
                    value=digest,
                )
                for key, (item_id, digest) in suite_constraints.items()
            )
        )

    for workspace in Workspace.objects.all():
        process_workspace(workspace, "pool-file")
        process_workspace(workspace, "build-id")


class Migration(migrations.Migration):
    dependencies = [
        ('db', '0068_remove_suites_from_archives'),
    ]

    operations = [
        migrations.RunPython(
            add_missing_archive_constraints, migrations.RunPython.noop
        )
    ]
