# Generated by Django 4.2.16 on 2024-10-21 17:35
import logging

from django.db import migrations
import django_migration_linter as linter

logger = logging.getLogger(__name__)

def populate_slack_channel(apps, schema_editor):
    OnCallSchedule = apps.get_model("schedules", "OnCallSchedule")
    SlackChannel = apps.get_model("slack", "SlackChannel")
    Organization = apps.get_model("user_management", "Organization")

    logger.info("Starting migration to populate slack_channel field.")

    # NOTE: the following raw SQL only works on mysql, fall back to the less-efficient (but working) ORM method
    # for non-mysql databases
    #
    # see the following references for more information:
    # https://github.com/grafana/oncall/issues/5244#issuecomment-2493688544
    # https://github.com/grafana/oncall/pull/5233/files#diff-d287631475456a42d005595383fb0b829cafb25aa15ed09b8e898b34803e59ef
    if schema_editor.connection.vendor == "mysql":
        sql = f"""
        UPDATE {OnCallSchedule._meta.db_table} AS ocs
        JOIN {Organization._meta.db_table} AS org ON org.id = ocs.organization_id
        JOIN {SlackChannel._meta.db_table} AS sc ON sc.slack_id = ocs.channel
                            AND sc.slack_team_identity_id = org.slack_team_identity_id
        SET ocs.slack_channel_id = sc.id
        WHERE ocs.channel IS NOT NULL
        AND org.slack_team_identity_id IS NOT NULL;
        """

        with schema_editor.connection.cursor() as cursor:
            cursor.execute(sql)
            updated_rows = cursor.rowcount  # Number of rows updated

        logger.info(f"Bulk updated {updated_rows} OnCallSchedules with their Slack channel.")
        logger.info("Finished migration to populate slack_channel field.")
    else:
        queryset = OnCallSchedule.objects.filter(channel__isnull=False, organization__slack_team_identity__isnull=False)
        total_schedules = queryset.count()
        updated_schedules = 0
        missing_channels = 0
        schedules_to_update = []

        logger.info(f"Total schedules to process: {total_schedules}")

        for schedule in queryset:
            slack_id = schedule.channel
            slack_team_identity = schedule.organization.slack_team_identity

            try:
                slack_channel = SlackChannel.objects.get(slack_id=slack_id, slack_team_identity=slack_team_identity)

                schedule.slack_channel = slack_channel
                schedules_to_update.append(schedule)

                updated_schedules += 1
                logger.info(
                    f"Schedule {schedule.id} updated with SlackChannel {slack_channel.id} (slack_id: {slack_id})."
                )
            except SlackChannel.DoesNotExist:
                missing_channels += 1
                logger.warning(
                    f"SlackChannel with slack_id {slack_id} and slack_team_identity {slack_team_identity} "
                    f"does not exist for Schedule {schedule.id}."
                )

        if schedules_to_update:
            OnCallSchedule.objects.bulk_update(schedules_to_update, ["slack_channel"])
            logger.info(f"Bulk updated {len(schedules_to_update)} OnCallSchedules with their Slack channel.")

        logger.info(
            f"Finished migration. Total schedules processed: {total_schedules}. "
            f"Schedules updated: {updated_schedules}. Missing SlackChannels: {missing_channels}."
        )

class Migration(migrations.Migration):

    dependencies = [
        ('schedules', '0018_oncallschedule_slack_channel'),
    ]

    operations = [
        # simply setting this new field is okay, we are not deleting the value of channel
        # therefore, no need to revert it
        linter.IgnoreMigration(),
        migrations.RunPython(populate_slack_channel, migrations.RunPython.noop),
    ]
