# Generated by Django 4.2.4 on 2023-08-19 18:34
import datetime

import pytz
from django.db import migrations, models


def compute_attacking_balance(transfer_amount, transfer_frac):
    # If the transfer_frac is 0, we have no info about the attacker's balance.
    if transfer_frac == 0:
        return None
    # The transfer amount was originally calculated as
    # transfer_amount = balance * transfer_frac,
    # so we just invert this.
    return int(transfer_amount / transfer_frac)


def compute_defending_balance(
    transfer_amount, transfer_frac, was_successful, attacker_transfer
):
    # We can only compute the defending balance if the attack was successful.
    if not was_successful or transfer_frac == 0:
        return None
    # The original defending transfer amount was calculated as...
    # attacking_transfer = attacking_balance * attacking_transfer_frac
    # defending_balance += attacking_transfer
    # defending_transfer = defending_balance * defending_transfer_frac
    # We need to invert this to compute the defending balance.
    defending_balance_plus_attacking_transfer = int(transfer_amount / transfer_frac)
    defending_balance = defending_balance_plus_attacking_transfer - attacker_transfer
    return defending_balance


def set_default_balances(apps, schema_editor):
    # Get the model from the versioned app registry to ensure the model is in its state at this migration.
    AuthAttempt = apps.get_model("gameui", "authattempt")
    pdt_timezone = pytz.timezone("America/Los_Angeles")

    for attempt in AuthAttempt.objects.all():
        has_post_prompt = len(attempt.defense_post_prompt) > 0
        attacking_transfer = attempt.attacking_transfer_amount
        defending_transfer = attempt.defending_transfer_amount

        timestamp = attempt.timestamp
        # We've had a few different ways of computing fees, so we need to match on timestamp.
        # A few of these calculations might be off if the attack happened at around the same time the
        # change went live on prod. All numbers are rounded to the nearest int,
        # so there will be some inaccuracy from that too.

        # Aug 10, 2023 10:06 PM PDT
        if timestamp < datetime.datetime(
            year=2023,
            month=8,
            day=10,
            hour=22,
            minute=6,
            second=0,
            microsecond=0,
            tzinfo=pdt_timezone,
        ):
            # 50% transfer defender -> attacker on success with post prompt, or 20% without.
            # 1% transfer attacker -> defender always. This is computed first.
            # (Some of these were created at a time post prompts were not allowed. All of those
            # should have the 50% transfer.)
            attacking_transfer_frac = 0.01
            defending_transfer_frac = 0.5 if has_post_prompt else 0.2
        # Aug 16, 2023 4:16 PM PDT
        elif timestamp < datetime.datetime(
            year=2023,
            month=8,
            day=16,
            hour=16,
            minute=16,
            second=0,
            microsecond=0,
            tzinfo=pdt_timezone,
        ):
            # 10% transfer defender -> attacker on success with post prompt, or 5% without.
            # .2% transfer attacker -> defender always. This is computed first.
            attacking_transfer_frac = 0.002
            defending_transfer_frac = 0.1 if has_post_prompt else 0.05
        else:
            # 10% transfer defender -> attacker on success with post prompt, or 5% without.
            # No login charge
            attacking_transfer_frac = 0
            defending_transfer_frac = 0.1 if has_post_prompt else 0.05

        attempt.attacking_balance = compute_attacking_balance(
            attacking_transfer, attacking_transfer_frac
        )
        attempt.defending_balance = compute_defending_balance(
            defending_transfer,
            defending_transfer_frac,
            attempt.was_successful,
            attacking_transfer,
        )
        attempt.save()


class Migration(migrations.Migration):
    dependencies = [
        (
            "gameui",
            "0034_account_shadow_balance_updated_at_and_more_squashed_0036_rename_stored_shadow_balance_account_shadow_balance",
        ),
    ]

    operations = [
        migrations.AddField(
            model_name="authattempt",
            name="attacking_balance",
            field=models.BigIntegerField(blank=True, null=True),
        ),
        migrations.AddField(
            model_name="authattempt",
            name="defending_balance",
            field=models.BigIntegerField(blank=True, null=True),
        ),
        # FIXME(sam): add this back in later. It fails in prod because it tries
        # to load EVERY AuthAttempt at once & exhausts memory.
        # migrations.RunPython(set_default_balances),
    ]
