# Generated by Django 5.2.14 on 2026-05-25 09:56

from tqdm import tqdm

from django.db import migrations


def get_markdownify_settings() -> dict:
    """Return the settings for markdownify, or an empty dict if not defined."""

    from django.conf import settings

    try:
        return settings.MARKDOWNIFY['default']
    except (AttributeError, KeyError):
        return {}


def markdown_to_html(value: str) -> str:
    """Convert a markdown string to HTML.

    This function will remove javascript and other potentially harmful content from the markdown string.
    """
    import markdown

    markdownify_settings = get_markdownify_settings()
    extensions = markdownify_settings.get('MARKDOWN_EXTENSIONS', [])
    extension_configs = markdownify_settings.get('MARKDOWN_EXTENSION_CONFIGS', {})

    html = markdown.markdown(
        value or '',
        extensions=extensions,
        extension_configs=extension_configs,
        output_format='html',
    )

    return html


def migrate_notes(apps, schema_editor):
    """Migrate existing notes to the new Note model."""

    ContentType = apps.get_model("contenttypes", "ContentType")

    # New target models
    Note = apps.get_model('common', 'Note')
    NotesImage = apps.get_model('common', 'NotesImage')

    for app, model in [
        ('build', 'build'),
        ('company', 'company'),
        ('company', 'manufacturerpart'),
        ('company', 'supplierpart'),
        ('order', 'purchaseorder'),
        ('order', 'returnorder'),
        ('order', 'salesorder'),
        ('order', 'salesordershipment'),
        ('order', 'transferorder'),
        ('part', 'part'),
        ('stock', 'stockitem'),
    ]:
        # Find old model which contains the 'notes' field
        OldModel = apps.get_model(app, model)
        with_notes = OldModel.objects.exclude(notes__isnull=True).exclude(notes='')
        content_type, _created = ContentType.objects.get_or_create(app_label=app, model=model)

        if not with_notes.exists():
            continue

        progress = tqdm(total=with_notes.count(), desc=f'Migration common.0045: Migrating notes for {app}.{model}')

        initial_note_count = Note.objects.count()
        expected_note_count = initial_note_count + with_notes.count()

        for instance in with_notes:

            content = markdown_to_html(instance.notes)

            note = Note.objects.create(
                title="Note",  # We don't have a title field in the old model, so we'll just use a default value
                content=content,
                model_type=content_type,
                model_id=instance.pk,
                primary=True
            )

            # Find any existing NotesImage objects associated with this instance
            images = NotesImage.objects.filter(model_type__iexact=model, model_id=instance.pk)
            images.update(note=note)

            # Find any notes images which do not directly reference the model instance, but are still referenced in the markdown content
            unlinked_images = NotesImage.objects.filter(
                note__isnull=True,
                model_id__isnull=True
            ).exclude(
                image__isnull=True
            )

            for image in unlinked_images:
                # If the image is referenced in the markdown content, link it to the note
                if image.image.url in instance.notes:
                    image.note = note
                    image.save()

            progress.update(1)

        assert Note.objects.count() == expected_note_count, f"Expected {expected_note_count} notes, but found {Note.objects.count()} after migration."


def remove_unlinked_images(apps, schema_editor):
    """Remove any NoteImage objects which are not linked to a Note instance."""

    NotesImage = apps.get_model('common', 'NotesImage')

    unlinked_images = NotesImage.objects.filter(note__isnull=True)

    for image in unlinked_images:
        image.delete()


class Migration(migrations.Migration):

    # Ensure that each app which supports 'notes' is up-to-date first
    dependencies = [
        ("build", "0059_build_tags"),
        ("common", "0046_note"),
        ("company", "0079_auto_20260212_1054"),
        ("order", "0119_transferorderlineitem_line_int"),
        ("part", "0150_part_maximum_stock"),
        ("stock", "0123_remove_stockitem_review_needed")
    ]

    operations = [
        migrations.RunPython(
            code=migrate_notes,
            reverse_code=migrations.RunPython.noop,
        ),
        migrations.RunPython(
            code=remove_unlinked_images,
            reverse_code=migrations.RunPython.noop,
        )
    ]
