# Generated by Django 5.1.12 on 2025-10-09 07:50

import json
import logging
import uuid

import django.db.models.deletion
from config.custom_logging import BackendLogger
from cryptography.fernet import Fernet
from django.conf import settings
from django.db import migrations, models

import api.rls
from api.db_router import MainRouter

logger = logging.getLogger(BackendLogger.API)


def migrate_lighthouse_configs_forward(apps, schema_editor):
    """
    Migrate data from old LighthouseConfiguration to new multi-provider models.
    Old system: one LighthouseConfiguration per tenant (always OpenAI).
    """
    LighthouseConfiguration = apps.get_model("api", "LighthouseConfiguration")
    LighthouseProviderConfiguration = apps.get_model(
        "api", "LighthouseProviderConfiguration"
    )
    LighthouseTenantConfiguration = apps.get_model(
        "api", "LighthouseTenantConfiguration"
    )
    LighthouseProviderModels = apps.get_model("api", "LighthouseProviderModels")

    fernet = Fernet(settings.SECRETS_ENCRYPTION_KEY.encode())

    # Migrate only tenants that actually have a LighthouseConfiguration
    for old_config in (
        LighthouseConfiguration.objects.using(MainRouter.admin_db)
        .select_related("tenant")
        .all()
    ):
        tenant = old_config.tenant
        tenant_id = str(tenant.id)

        try:
            # Create OpenAI provider configuration for this tenant
            api_key_decrypted = fernet.decrypt(bytes(old_config.api_key)).decode()
            credentials_encrypted = fernet.encrypt(
                json.dumps({"api_key": api_key_decrypted}).encode()
            )
            provider_config = LighthouseProviderConfiguration.objects.using(
                MainRouter.admin_db
            ).create(
                tenant=tenant,
                provider_type="openai",
                credentials=credentials_encrypted,
                is_active=old_config.is_active,
            )

            # Create tenant configuration from old values
            LighthouseTenantConfiguration.objects.using(MainRouter.admin_db).create(
                tenant=tenant,
                business_context=old_config.business_context or "",
                default_provider="openai",
                default_models={"openai": old_config.model},
            )

            # Create initial provider model record
            LighthouseProviderModels.objects.using(MainRouter.admin_db).create(
                tenant=tenant,
                provider_configuration=provider_config,
                model_id=old_config.model,
                model_name=old_config.model,
                default_parameters={},
            )

        except Exception:
            logger.exception(
                "Failed to migrate lighthouse config for tenant %s", tenant_id
            )
            continue


class Migration(migrations.Migration):
    dependencies = [
        ("api", "0049_compliancerequirementoverview_passed_failed_findings"),
    ]

    operations = [
        migrations.CreateModel(
            name="LighthouseProviderConfiguration",
            fields=[
                (
                    "id",
                    models.UUIDField(
                        default=uuid.uuid4,
                        editable=False,
                        primary_key=True,
                        serialize=False,
                    ),
                ),
                ("inserted_at", models.DateTimeField(auto_now_add=True)),
                ("updated_at", models.DateTimeField(auto_now=True)),
                (
                    "provider_type",
                    models.CharField(
                        choices=[("openai", "OpenAI")],
                        help_text="LLM provider name",
                        max_length=50,
                    ),
                ),
                ("base_url", models.URLField(blank=True, null=True)),
                (
                    "credentials",
                    models.BinaryField(
                        help_text="Encrypted JSON credentials for the provider"
                    ),
                ),
                ("is_active", models.BooleanField(default=True)),
            ],
            options={
                "db_table": "lighthouse_provider_configurations",
                "abstract": False,
            },
        ),
        migrations.CreateModel(
            name="LighthouseProviderModels",
            fields=[
                (
                    "id",
                    models.UUIDField(
                        default=uuid.uuid4,
                        editable=False,
                        primary_key=True,
                        serialize=False,
                    ),
                ),
                ("inserted_at", models.DateTimeField(auto_now_add=True)),
                ("updated_at", models.DateTimeField(auto_now=True)),
                ("model_id", models.CharField(max_length=100)),
                ("model_name", models.CharField(max_length=100)),
                ("default_parameters", models.JSONField(blank=True, default=dict)),
            ],
            options={
                "db_table": "lighthouse_provider_models",
                "abstract": False,
            },
        ),
        migrations.CreateModel(
            name="LighthouseTenantConfiguration",
            fields=[
                (
                    "id",
                    models.UUIDField(
                        default=uuid.uuid4,
                        editable=False,
                        primary_key=True,
                        serialize=False,
                    ),
                ),
                ("inserted_at", models.DateTimeField(auto_now_add=True)),
                ("updated_at", models.DateTimeField(auto_now=True)),
                ("business_context", models.TextField(blank=True, default="")),
                ("default_provider", models.CharField(blank=True, max_length=50)),
                ("default_models", models.JSONField(blank=True, default=dict)),
            ],
            options={
                "db_table": "lighthouse_tenant_config",
                "abstract": False,
            },
        ),
        migrations.AddField(
            model_name="lighthouseproviderconfiguration",
            name="tenant",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
            ),
        ),
        migrations.AddField(
            model_name="lighthouseprovidermodels",
            name="provider_configuration",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE,
                related_name="available_models",
                to="api.lighthouseproviderconfiguration",
            ),
        ),
        migrations.AddField(
            model_name="lighthouseprovidermodels",
            name="tenant",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
            ),
        ),
        migrations.AddField(
            model_name="lighthousetenantconfiguration",
            name="tenant",
            field=models.ForeignKey(
                on_delete=django.db.models.deletion.CASCADE, to="api.tenant"
            ),
        ),
        migrations.AddIndex(
            model_name="lighthouseproviderconfiguration",
            index=models.Index(
                fields=["tenant_id", "provider_type"], name="lh_pc_tenant_type_idx"
            ),
        ),
        migrations.AddConstraint(
            model_name="lighthouseproviderconfiguration",
            constraint=api.rls.RowLevelSecurityConstraint(
                "tenant_id",
                name="rls_on_lighthouseproviderconfiguration",
                statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
            ),
        ),
        migrations.AddConstraint(
            model_name="lighthouseproviderconfiguration",
            constraint=models.UniqueConstraint(
                fields=("tenant_id", "provider_type"),
                name="unique_provider_config_per_tenant",
            ),
        ),
        migrations.AddIndex(
            model_name="lighthouseprovidermodels",
            index=models.Index(
                fields=["tenant_id", "provider_configuration"],
                name="lh_prov_models_cfg_idx",
            ),
        ),
        migrations.AddConstraint(
            model_name="lighthouseprovidermodels",
            constraint=api.rls.RowLevelSecurityConstraint(
                "tenant_id",
                name="rls_on_lighthouseprovidermodels",
                statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
            ),
        ),
        migrations.AddConstraint(
            model_name="lighthouseprovidermodels",
            constraint=models.UniqueConstraint(
                fields=("tenant_id", "provider_configuration", "model_id"),
                name="unique_provider_model_per_configuration",
            ),
        ),
        migrations.AddConstraint(
            model_name="lighthousetenantconfiguration",
            constraint=api.rls.RowLevelSecurityConstraint(
                "tenant_id",
                name="rls_on_lighthousetenantconfiguration",
                statements=["SELECT", "INSERT", "UPDATE", "DELETE"],
            ),
        ),
        migrations.AddConstraint(
            model_name="lighthousetenantconfiguration",
            constraint=models.UniqueConstraint(
                fields=("tenant_id",), name="unique_tenant_lighthouse_config"
            ),
        ),
        # Migrate data from old LighthouseConfiguration to new tables
        # This runs after all tables, indexes, and constraints are created
        # The old Lighthouse configuration table is not removed, so reverse_code is noop
        # During rollbacks, the old Lighthouse configuration remains intact while the new tables are removed
        migrations.RunPython(
            migrate_lighthouse_configs_forward,
            reverse_code=migrations.RunPython.noop,
        ),
    ]
