# Copyright 2025 Laurent Defert
#
#  This file is part of Sosse.
#
# Sosse is free software: you can redistribute it and/or modify it under the terms of the GNU Affero
# General Public License as published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# Sosse is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
# the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
# See the GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License along with Sosse.
# If not, see <https://www.gnu.org/licenses/>.

# Generated by Django 3.2.19 on 2025-08-19 13:52

from django.db import connection, migrations
from django.db.models.fields.reverse_related import (
    ManyToManyRel,
    ManyToOneRel,
    OneToOneRel,
)


def copy_model(source_model_name, target_model_name, apps):
    Tag = apps.get_model("se", "Tag")
    Webhook = apps.get_model("se", "Webhook")
    target_model = apps.get_model("se", target_model_name)
    source_model = apps.get_model("se", source_model_name)

    if source_model_name == "CrawlPolicy":
        source_auth_model = apps.get_model("se", "AuthField")
        target_auth_model = apps.get_model("se", "AuthFieldBackup")
    else:
        target_auth_model = apps.get_model("se", "AuthField")
        source_auth_model = apps.get_model("se", "AuthFieldBackup")

    target_auth_model.objects.all().delete()

    if source_model_name == "CrawlPolicy":
        target_model.objects.all().delete()
    else:
        # CrawlPolicy's definition is not available (in the code) we can't delete() it
        with connection.cursor() as cursor:
            cursor.execute("TRUNCATE TABLE se_crawlpolicy_tags, se_crawlpolicy_webhooks, se_crawlpolicy CASCADE;")

    fields = [
        field.name
        for field in apps.get_model("se", "CrawlPolicyBackup")._meta.get_fields()
        if field.name not in ("id", "tags", "webhooks")
        and not isinstance(field, (ManyToOneRel, ManyToManyRel, OneToOneRel))
    ]

    for source_instance in source_model.objects.all():
        target_instance = target_model()
        for field in fields:
            setattr(target_instance, field, getattr(source_instance, field))
        target_instance.save()

        for source_auth in source_auth_model.objects.filter(crawl_policy=source_instance):
            target_auth = target_auth_model()
            target_auth.key = source_auth.key
            target_auth.value = source_auth.value
            target_auth.crawl_policy_id = target_instance.id
            target_auth.save()

        if source_model_name == "CrawlPolicy":
            # Backup: save ManyToMany as ArrayField
            target_instance.tags = list(source_instance.tags.values_list("name", flat=True))
            target_instance.webhooks = list(source_instance.webhooks.values_list("name", flat=True))
            target_instance.save(update_fields=["tags", "webhooks"])
        else:
            # Restore: restore ArrayField to ManyToMany
            target_instance.tags.set(Tag.objects.filter(name__in=source_instance.tags))
            target_instance.webhooks.set(Webhook.objects.filter(name__in=source_instance.webhooks))


def backup_crawl_policy(apps, schema_editor):
    copy_model("CrawlPolicy", "CrawlPolicyBackup", apps)


def restore_crawl_policy(apps, schema_editor):
    copy_model("CrawlPolicyBackup", "CrawlPolicy", apps)


class Migration(migrations.Migration):
    dependencies = [
        ("se", "0018_crawl_policy_backup"),
    ]

    operations = [
        migrations.RunPython(backup_crawl_policy, restore_crawl_policy),
    ]
