# Generated by Django 5.2.11 on 2026-06-27 17:18

import django.db.models.deletion
from django.db import migrations, models


def _raw_data_to_blob(apps, schema_editor):
    """Preserve in-flight queue rows across the raw_data -> blob switch.

    Rows queued by the pre-blob code hold their only copy of the message in the
    inline ``raw_data`` column, so committing each to a Blob here keeps
    in-flight / deferred / abandoned mail from being lost when ``raw_data`` is
    dropped below. No-op on a fresh database (empty queue), so the real
    ``create_blob`` (imported lazily) only runs on an actual upgrade, where the
    current code is authoritative.
    """
    # pylint: disable=import-outside-toplevel
    from core.models import Blob

    InboundMessage = apps.get_model("core", "inboundmessage")
    rows = InboundMessage.objects.filter(blob__isnull=True).exclude(raw_data=None)
    for inbound in rows.iterator():
        raw = bytes(inbound.raw_data) if inbound.raw_data else b""
        if not raw:
            continue
        blob = Blob.objects.create_blob(content=raw, content_type="message/rfc822")
        # Assign by id: the real Blob instance isn't an instance of the
        # historical Blob model ``apps.get_model`` gave InboundMessage.blob.
        inbound.blob_id = blob.id
        inbound.save(update_fields=["blob"])


class Migration(migrations.Migration):

    dependencies = [
        ('core', '0031_message_mime_id_index'),
    ]

    operations = [
        migrations.AddField(
            model_name='inboundmessage',
            name='abandoned_at',
            field=models.DateTimeField(blank=True, help_text='When processing was permanently abandoned; NULL while live.', null=True, verbose_name='abandoned at'),
        ),
        migrations.AddIndex(
            model_name='inboundmessage',
            index=models.Index(condition=models.Q(('abandoned_at__isnull', False)), fields=['abandoned_at'], name='messages_in_abandon_partial'),
        ),
        migrations.AddField(
            model_name='inboundmessage',
            name='blob',
            field=models.ForeignKey(blank=True, help_text='Content-addressed blob holding the raw message bytes.', null=True, on_delete=django.db.models.deletion.PROTECT, related_name='inbound_messages', to='core.blob'),
        ),
        migrations.AddField(
            model_name='inboundmessage',
            name='envelope',
            field=models.JSONField(blank=True, default=dict, help_text='Structured SMTP/provenance envelope for this delivery.', verbose_name='envelope'),
        ),
        # Move in-flight rows' bytes into a blob BEFORE dropping raw_data, so
        # no queued/deferred/abandoned message is lost on upgrade.
        migrations.RunPython(_raw_data_to_blob, migrations.RunPython.noop),
        migrations.RemoveField(
            model_name='inboundmessage',
            name='raw_data',
        ),
        migrations.AddField(
            model_name='message',
            name='postmark',
            field=models.JSONField(blank=True, help_text='Sparse per-delivery pipeline record.', null=True, verbose_name='postmark'),
        ),
    ]
