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

"""Data migration to populate ``Token.(activating_)worker``."""

from django.db import migrations
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
from django.db.migrations.state import StateApps
from django.db.models import OuterRef, Subquery

from debusine.db.models.auth import _TokenTypes


def set_token_type_and_workers(
    apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
) -> None:
    """Set ``Token.worker`` and ``Token.activating_worker`."""
    Token = apps.get_model("db", "Token")
    Worker = apps.get_model("db", "Worker")

    for worker_column, token_column in (
        ("token", "_worker_id"),
        ("activation_token", "_activating_worker_id"),
    ):
        Token.objects.filter(
            id__in=Worker.objects.filter(
                **{f"{worker_column}__isnull": False}
            ).values(worker_column)
        ).update(
            **{
                token_column: Subquery(
                    Worker.objects.filter(
                        **{worker_column: OuterRef("id")}
                    ).values("id")
                )
            }
        )

    Token.objects.filter(_activating_worker_id__isnull=False).update(
        token_type=_TokenTypes.WORKER_ACTIVATION
    )
    Token.objects.filter(_worker_id__isnull=False).update(
        token_type=_TokenTypes.WORKER
    )
    Token.objects.filter(user__isnull=False).update(token_type=_TokenTypes.USER)

    # Delete any remaining bare tokens.  They can't be used for anything any
    # more, and the next database migration will add a constraint forbidding
    # them.
    Token.objects.filter(token_type="").delete()


def clear_token_type_and_workers(
    apps: StateApps, schema_editor: BaseDatabaseSchemaEditor
) -> None:
    """Clear ``Token.worker`` and ``Token.activating_worker`."""
    Token = apps.get_model("db", "Token")
    Token.objects.update(
        token_type="", _worker_id=None, _activating_worker_id=None
    )


class Migration(migrations.Migration):
    dependencies = [
        ("db", "0048_mirror_worker_token_ids"),
    ]

    operations = [
        migrations.RunPython(
            set_token_type_and_workers, clear_token_type_and_workers
        ),
    ]
