# fortunaisk/migrations/0007_add_new_schema_squashed_0020_alter_ticketanomaly_detail.py
# Generated by Django 4.2.20 on 2025-05-30 13:34

# Standard Library
from decimal import Decimal

# Django
import django.db.migrations.operations.special
import django.db.models.deletion
import django.utils.timezone
from django.conf import settings
from django.db import migrations, models


def check_table_exists(cursor, table_name):
    """Vérifie si une table existe"""
    cursor.execute(f"SHOW TABLES LIKE '{table_name}'")
    return cursor.fetchone() is not None


def check_column_exists(cursor, table_name, column_name):
    """Vérifie si une colonne existe dans une table"""
    cursor.execute(f"SHOW COLUMNS FROM {table_name} LIKE '{column_name}'")
    return cursor.fetchone() is not None


def safe_create_table_winnerdistribution(apps, schema_editor):
    """Crée la table WinnerDistribution seulement si elle n'existe pas"""
    with schema_editor.connection.cursor() as cursor:
        if not check_table_exists(cursor, 'fortunaisk_winnerdistribution'):
            WinnerDistribution = apps.get_model("fortunaisk", "WinnerDistribution")
            schema_editor.create_model(WinnerDistribution)


def safe_add_field(apps, schema_editor, model_name, field_name, field):
    """Ajoute un champ seulement s'il n'existe pas déjà"""
    model = apps.get_model("fortunaisk", model_name)
    table_name = model._meta.db_table
    
    with schema_editor.connection.cursor() as cursor:
        if not check_column_exists(cursor, table_name, field_name):
            schema_editor.add_field(model, field)


def safe_remove_field(apps, schema_editor, model_name, field_name):
    """Supprime un champ seulement s'il existe"""
    model = apps.get_model("fortunaisk", model_name)
    table_name = model._meta.db_table
    
    with schema_editor.connection.cursor() as cursor:
        if check_column_exists(cursor, table_name, field_name):
            # Créer un field factice pour la suppression
            field = models.CharField(max_length=100)
            field.set_attributes_from_name(field_name)
            schema_editor.remove_field(model, field)


# Fonctions migrées des migrations d'origine
def forwards_func(apps, schema_editor):
    """
    Migration 0008: Transfert des données des anciens modèles vers les nouveaux.
    """
    # Récupérer les modèles
    AutoLottery = apps.get_model("fortunaisk", "AutoLottery")
    Lottery = apps.get_model("fortunaisk", "Lottery")
    WinnerDistribution = apps.get_model("fortunaisk", "WinnerDistribution")

    # Migrer les distributions de gagnants
    for lottery in Lottery.objects.all():
        if not lottery.winners_distribution:
            continue

        try:
            # Check if winners_distribution is already a list
            if isinstance(lottery.winners_distribution, list):
                distributions = [str(d) for d in lottery.winners_distribution]
            else:
                distributions = lottery.winners_distribution.split(",")

            for idx, dist in enumerate(distributions, 1):
                dist = str(dist).strip()
                if not dist:
                    continue

                WinnerDistribution.objects.create(
                    lottery_reference=lottery.lottery_reference,
                    winner_rank=idx,
                    winner_prize_distribution=Decimal(dist.strip("%")),
                )
        except Exception as e:
            print(f"Erreur migration lottery {lottery.pk}: {e}")

    # Migrer les distributions d'auto-loteries
    for auto in AutoLottery.objects.all():
        if not auto.winners_distribution:
            continue

        try:
            # Check if winners_distribution is already a list
            if isinstance(auto.winners_distribution, list):
                # Already in the correct format, skip
                continue
            else:
                # Convertir en liste JSON
                distributions = auto.winners_distribution.split(",")
                auto.winners_distribution = [
                    float(d.strip("%")) for d in distributions if d.strip()
                ]
                auto.save()
        except Exception as e:
            print(f"Erreur migration autolottery {auto.pk}: {e}")


def fill_processedpayment_fields(apps, schema_editor):
    """
    Migration 0009: Remplissage des champs user/character dans ProcessedPayment.
    """
    ProcessedPayment = apps.get_model("fortunaisk", "ProcessedPayment")
    TicketPurchase = apps.get_model("fortunaisk", "TicketPurchase")

    # Mettre à jour les paiements traités avec les utilisateurs et personnages correspondants
    for payment in ProcessedPayment.objects.all():
        tickets = TicketPurchase.objects.filter(payment_id=payment.payment_id)
        if tickets.exists():
            ticket = tickets.first()
            payment.user = ticket.user
            payment.character = ticket.character
            payment.payed_at = getattr(ticket, "created_at", None) or getattr(
                ticket, "purchase_date", None
            )
            payment.amount = getattr(ticket, "amount", None) or (
                ticket.price * ticket.quantity
            )
            payment.save()


def convert_notification_config(apps, schema_editor):
    """
    Migration 0016: Conversion du champ notification_config des WebhookConfiguration
    """
    WebhookConfiguration = apps.get_model("fortunaisk", "WebhookConfiguration")

    for webhook in WebhookConfiguration.objects.all():
        try:
            config = webhook.notification_config
            if isinstance(config, dict):
                events = config.get("events", [])
                ping_roles = config.get("ping_roles", [])

                # Mettre à jour avec la nouvelle structure
                webhook.notification_config = events
                webhook.ping_roles = ping_roles
                webhook.save()
        except Exception as e:
            print(f"Erreur conversion webhook {webhook.pk}: {e}")


def set_default_webhook_name(apps, schema_editor):
    """
    Migration 0017: Définir des noms par défaut pour les webhooks
    """
    WebhookConfiguration = apps.get_model("fortunaisk", "WebhookConfiguration")

    for idx, webhook in enumerate(WebhookConfiguration.objects.filter(name=""), 1):
        webhook.name = f"Webhook Configuration {idx}"
        webhook.save()


def set_empty_detail(apps, schema_editor):
    """
    Migration 0018: Remplacer les valeurs NULL par une chaîne vide dans TicketAnomaly.detail
    """
    TicketAnomaly = apps.get_model("fortunaisk", "TicketAnomaly")

    TicketAnomaly.objects.filter(detail__isnull=True).update(detail="")


def fix_ping_roles(apps, schema_editor):
    """
    Migration 0019: Corriger le format des ping_roles dans WebhookConfiguration
    """
    WebhookConfiguration = apps.get_model("fortunaisk", "WebhookConfiguration")

    for webhook in WebhookConfiguration.objects.all():
        roles = webhook.ping_roles
        if isinstance(roles, str):
            try:
                # Tenter de convertir une chaîne en liste
                webhook.ping_roles = [
                    role.strip() for role in roles.split(",") if role.strip()
                ]
                webhook.save()
            except Exception as e:
                print(f"Erreur correction ping_roles {webhook.pk}: {e}")
                webhook.ping_roles = []
                webhook.save()


class Migration(migrations.Migration):

    replaces = [
        ("fortunaisk", "0007_add_new_schema"),
        ("fortunaisk", "0008_migrate_data"),
        ("fortunaisk", "0009_fill_processedpayment_fields"),
        ("fortunaisk", "0010_autolottery_tax_lottery_tax"),
        ("fortunaisk", "0011_autolottery_tax_amount_lottery_tax_amount"),
        ("fortunaisk", "0012_alter_autolottery_winners_distribution_and_more"),
        ("fortunaisk", "0013_remove_lottery_winners_distribution"),
        ("fortunaisk", "0014_alter_webhookconfiguration_options_and_more"),
        ("fortunaisk", "0015_alter_webhookconfiguration_options_and_more"),
        ("fortunaisk", "0016_convert_notification_config"),
        ("fortunaisk", "0017_fill_webhook_names"),
        ("fortunaisk", "0018_fill_detail_empty"),
        ("fortunaisk", "0019_fix_ping_roles"),
        ("fortunaisk", "0020_alter_ticketanomaly_detail"),
    ]

    dependencies = [
        ("eveonline", "0017_alliance_and_corp_names_are_not_unique"),
        migrations.swappable_dependency(settings.AUTH_USER_MODEL),
        ("fortunaisk", "0006_lowercase_interval_period"),
    ]

    operations = [
        # Création conditionnelle de la table WinnerDistribution
        migrations.RunSQL(
            """
            CREATE TABLE IF NOT EXISTS fortunaisk_winnerdistribution (
                id BIGINT AUTO_INCREMENT PRIMARY KEY,
                lottery_reference VARCHAR(20) NOT NULL,
                winner_rank INT UNSIGNED NOT NULL,
                winner_prize_distribution DECIMAL(5,2) NOT NULL,
                created_at DATETIME(6) NOT NULL,
                updated_at DATETIME(6) NOT NULL,
                INDEX fortunaisk_winnerdistribution_lottery_reference_idx (lottery_reference)
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
            """,
            reverse_sql="DROP TABLE IF EXISTS fortunaisk_winnerdistribution;"
        ),
        
        # Ajout conditionnel des champs ProcessedPayment
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_processedpayment ADD COLUMN IF NOT EXISTS character_id BIGINT NULL;",
            reverse_sql="ALTER TABLE fortunaisk_processedpayment DROP COLUMN IF EXISTS character_id;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_processedpayment ADD COLUMN IF NOT EXISTS user_id INT NULL;",
            reverse_sql="ALTER TABLE fortunaisk_processedpayment DROP COLUMN IF EXISTS user_id;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_processedpayment ADD COLUMN IF NOT EXISTS amount DECIMAL(25,2) NOT NULL DEFAULT '0.00';",
            reverse_sql="ALTER TABLE fortunaisk_processedpayment DROP COLUMN IF EXISTS amount;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_processedpayment ADD COLUMN IF NOT EXISTS payed_at DATETIME(6) NULL;",
            reverse_sql="ALTER TABLE fortunaisk_processedpayment DROP COLUMN IF EXISTS payed_at;"
        ),
        
        # Ajout conditionnel des champs TicketAnomaly
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_ticketanomaly ADD COLUMN IF NOT EXISTS solved TINYINT(1) NOT NULL DEFAULT 0;",
            reverse_sql="ALTER TABLE fortunaisk_ticketanomaly DROP COLUMN IF EXISTS solved;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_ticketanomaly ADD COLUMN IF NOT EXISTS solved_at DATETIME(6) NULL;",
            reverse_sql="ALTER TABLE fortunaisk_ticketanomaly DROP COLUMN IF EXISTS solved_at;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_ticketanomaly ADD COLUMN IF NOT EXISTS solved_by_id INT NULL;",
            reverse_sql="ALTER TABLE fortunaisk_ticketanomaly DROP COLUMN IF EXISTS solved_by_id;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_ticketanomaly ADD COLUMN IF NOT EXISTS detail LONGTEXT NULL;",
            reverse_sql="ALTER TABLE fortunaisk_ticketanomaly DROP COLUMN IF EXISTS detail;"
        ),
        
        # Ajout conditionnel des champs Winner
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_winner ADD COLUMN IF NOT EXISTS distributed_at DATETIME(6) NULL;",
            reverse_sql="ALTER TABLE fortunaisk_winner DROP COLUMN IF EXISTS distributed_at;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_winner ADD COLUMN IF NOT EXISTS distributed_by_id INT NULL;",
            reverse_sql="ALTER TABLE fortunaisk_winner DROP COLUMN IF EXISTS distributed_by_id;"
        ),
        
        # Ajout conditionnel des champs WebhookConfiguration
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_webhookconfiguration ADD COLUMN IF NOT EXISTS notification_config JSON NULL;",
            reverse_sql="ALTER TABLE fortunaisk_webhookconfiguration DROP COLUMN IF EXISTS notification_config;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_webhookconfiguration ADD COLUMN IF NOT EXISTS created_at DATETIME(6) NOT NULL DEFAULT NOW(6);",
            reverse_sql="ALTER TABLE fortunaisk_webhookconfiguration DROP COLUMN IF EXISTS created_at;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_webhookconfiguration ADD COLUMN IF NOT EXISTS created_by_id INT NULL;",
            reverse_sql="ALTER TABLE fortunaisk_webhookconfiguration DROP COLUMN IF EXISTS created_by_id;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_webhookconfiguration ADD COLUMN IF NOT EXISTS name VARCHAR(100) NOT NULL DEFAULT '';",
            reverse_sql="ALTER TABLE fortunaisk_webhookconfiguration DROP COLUMN IF EXISTS name;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_webhookconfiguration ADD COLUMN IF NOT EXISTS ping_roles JSON NULL;",
            reverse_sql="ALTER TABLE fortunaisk_webhookconfiguration DROP COLUMN IF EXISTS ping_roles;"
        ),
        
        # Ajout conditionnel des champs AutoLottery et Lottery
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_autolottery ADD COLUMN IF NOT EXISTS tax DECIMAL(5,2) NOT NULL DEFAULT '0.00';",
            reverse_sql="ALTER TABLE fortunaisk_autolottery DROP COLUMN IF EXISTS tax;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_autolottery ADD COLUMN IF NOT EXISTS tax_amount DECIMAL(25,2) NOT NULL DEFAULT '0.00';",
            reverse_sql="ALTER TABLE fortunaisk_autolottery DROP COLUMN IF EXISTS tax_amount;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_lottery ADD COLUMN IF NOT EXISTS tax DECIMAL(5,2) NOT NULL DEFAULT '0.00';",
            reverse_sql="ALTER TABLE fortunaisk_lottery DROP COLUMN IF EXISTS tax;"
        ),
        migrations.RunSQL(
            "ALTER TABLE fortunaisk_lottery ADD COLUMN IF NOT EXISTS tax_amount DECIMAL(25,2) NOT NULL DEFAULT '0.00';",
            reverse_sql="ALTER TABLE fortunaisk_lottery DROP COLUMN IF EXISTS tax_amount;"
        ),
        
        # Ajout des contraintes de clés étrangères si elles n'existent pas
        migrations.RunSQL(
            """
            SET @constraint_name = (SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS 
                                  WHERE TABLE_NAME = 'fortunaisk_processedpayment' AND COLUMN_NAME = 'character_id');
            SET @sql = IF(@constraint_name IS NULL, 
                         'ALTER TABLE fortunaisk_processedpayment ADD CONSTRAINT fortunaisk_processedpayment_character_id_fk FOREIGN KEY (character_id) REFERENCES eveonline_evecharacter(character_id)',
                         'SELECT "Constraint already exists"');
            PREPARE stmt FROM @sql;
            EXECUTE stmt;
            DEALLOCATE PREPARE stmt;
            """,
            reverse_sql=migrations.RunSQL.noop
        ),
        
        migrations.RunPython(
            code=forwards_func,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.RunPython(
            code=fill_processedpayment_fields,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.RunPython(
            code=convert_notification_config,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.RunPython(
            code=set_default_webhook_name,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.RunPython(
            code=set_empty_detail,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
        migrations.RunPython(
            code=fix_ping_roles,
            reverse_code=django.db.migrations.operations.special.RunPython.noop,
        ),
    ]
