"""
Rough cost of the two #33586 fix options on a synthetic project.

Each model has a FK to a shared "User"-like hub and to a random earlier model,
so the models form one connected graph (as real projects do via auth and
contenttypes).

- Option 1 cost: clear_delayed_apps_cache() + re-render of the whole registry,
  paid once per backwards RunPython whose from_state is delayed.
- Option 2 cost: reload_model(delay=False) instead of delay=True, paid on every
  options-style operation in both directions.
"""

import random
import sys
import timeit

import django
from django.conf import settings

settings.configure(INSTALLED_APPS=[])
django.setup()

from django.db import models
from django.db.migrations.state import ModelState, ProjectState


def build(n):
    rnd = random.Random(0)
    state = ProjectState()
    state.add_model(
        ModelState("app", "Hub", [("id", models.AutoField(primary_key=True))])
    )
    for i in range(n):
        fields = [("id", models.AutoField(primary_key=True))]
        if HUB:
            fields.append(("hub", models.ForeignKey("app.Hub", models.CASCADE)))
        if i:
            fields.append(
                ("prev", models.ForeignKey(f"app.M{rnd.randrange(i)}", models.CASCADE))
            )
        state.add_model(ModelState("app", f"M{i}", fields))
    return state


HUB = sys.argv[1] == "hub"
print("graph:", "every model -> Hub + random earlier model" if HUB else "random earlier model only")
for n in [int(x) for x in sys.argv[2:]] or [100, 300, 1000]:
    state = build(n)
    state.apps
    target = f"m{n // 2}"

    def full_render():
        s = state.clone()
        s.is_delayed = True
        s.clear_delayed_apps_cache()
        s.apps

    def reload_delayed():
        state.reload_model("app", target, delay=True)

    def reload_recursive():
        state.reload_model("app", target, delay=False)

    reps = 3
    print(
        f"n={n:5d}  "
        f"full re-render (option 1): {min(timeit.repeat(full_render, number=1, repeat=reps)):.3f}s  "
        f"delay=True reload (today): {min(timeit.repeat(reload_delayed, number=1, repeat=reps)):.3f}s  "
        f"delay=False reload (option 2): {min(timeit.repeat(reload_recursive, number=1, repeat=reps)):.3f}s"
    )
