# Generated by Django 5.2 on 2025-05-25 22:01
import logging
from django.db import transaction
from itertools import groupby

import django.utils.timezone
from django.db import migrations, models

logger = logging.getLogger(__name__)

BATCH_SIZE = 1_000

def convert_repeats_to_instances(apps, schema_editor):
    Episode = apps.get_model('app', 'Episode')
    HistoricalEpisode = apps.get_model('app', 'HistoricalEpisode')

    # Grab repeat episodes once so we can delete them later
    episodes_qs = (
        Episode.objects
        .filter(repeats__gt=0)
        .select_related('item', 'related_season')
        .order_by('pk')
    )

    episode_ids = list(episodes_qs.values_list('pk', flat=True))

    # Prefetch all historic rows, grouped by original episode id
    history_qs = (
        HistoricalEpisode.objects
        .filter(id__in=episode_ids)
        .order_by('id', 'history_date')
    )

    grouped_history = {
        ep_id: list(records)
        for ep_id, records in groupby(history_qs, key=lambda h: h.id)
    }

    with transaction.atomic():
        # We collect (Episode instance, HistoricalEpisode template) pairs
        pair_buffer = []

        for episode in episodes_qs.iterator():
            for hist in grouped_history.get(episode.pk, []):
                pair_buffer.append(
                    (
                        Episode(
                            item=episode.item,
                            related_season=episode.related_season,
                            end_date=hist.end_date,
                            repeats=0,
                        ),
                        hist,  # keep a reference to the historic row
                    )
                )

                # Flush when the batch limit is hit
                if len(pair_buffer) >= BATCH_SIZE:
                    _flush_pairs(pair_buffer, Episode, HistoricalEpisode)
                    pair_buffer.clear()

        # Flush leftovers
        if pair_buffer:
            _flush_pairs(pair_buffer, Episode, HistoricalEpisode)

        # Delete the originals in bulk
        Episode.objects.filter(pk__in=episode_ids).delete()


def _flush_pairs(pair_buffer, Episode, HistoricalEpisode):
    """
    Helper that:
      1. bulk_inserts the Episode objects
      2. builds & bulk_inserts the corresponding HistoricalEpisode objects
    """

    # 1) Bulk insert episodes and fetch auto IDs
    episodes_to_create = [pair[0] for pair in pair_buffer]
    created_episodes = Episode.objects.bulk_create(
        episodes_to_create,
        batch_size=BATCH_SIZE,
    )

    # 2) Build matching historic rows
    historical_to_create = []
    for created_ep, (_, hist_template) in zip(created_episodes, pair_buffer):
        historical_to_create.append(
            HistoricalEpisode(
                id=created_ep.pk,         # required by django-simple-history
                history_date=hist_template.history_date,
                history_type='+',
                history_user=hist_template.history_user,
                end_date=hist_template.end_date,
                repeats=0,
            )
        )

    HistoricalEpisode.objects.bulk_create(
        historical_to_create,
        batch_size=BATCH_SIZE
    )

class Migration(migrations.Migration):

    dependencies = [
        ('app', '0044_fix_episode_images'),
    ]

    operations = [
        migrations.AddField(
            model_name='anime',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='basicmedia',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='book',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='comic',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='episode',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='game',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='manga',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='movie',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='season',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AddField(
            model_name='tv',
            name='created_at',
            field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
            preserve_default=False,
        ),
        migrations.AlterModelOptions(
            name='episode',
            options={},
        ),
        migrations.RemoveConstraint(
            model_name='episode',
            name='app_episode_unique_season_item',
        ),
        migrations.RunPython(
            convert_repeats_to_instances,
            reverse_code=migrations.RunPython.noop
        ),
    ]
