"""Wipe the configured database and re-run all migrations from scratch.

Intended for ephemeral environments (staging) where losing every user, room,
billpost, token, etc. is acceptable. Refuses to run when DEBUG=False unless
the operator explicitly confirms with --i-mean-it, and always prints the
DB host before doing anything destructive.

Typical staging usage from the deploy host:

    docker exec -it gamearray python manage.py reset_staging_db --i-mean-it

Locally (sqlite, DEBUG=True) the safety prompt is skipped:

    python src/manage.py reset_staging_db
"""
from django.conf import settings
from django.core.management import call_command
from django.core.management.base import BaseCommand, CommandError
from django.db import connection


PROD_HOST_FRAGMENTS = ("earthmanrpg.me",)


class Command(BaseCommand):
    help = "Drop every table in the default DB and re-run migrations. Destructive."

    def add_arguments(self, parser):
        parser.add_argument(
            "--i-mean-it",
            action="store_true",
            help="Required when DEBUG=False. Bypasses the interactive confirmation.",
        )
        parser.add_argument(
            "--no-superuser",
            action="store_true",
            help="Skip the post-migrate ensure_superuser call.",
        )

    def handle(self, *args, **opts):
        db_settings = settings.DATABASES["default"]
        engine = db_settings.get("ENGINE", "")
        host = db_settings.get("HOST") or db_settings.get("NAME") or "(unknown)"

        # Refuse outright if the host name suggests production
        if any(frag in str(host) for frag in PROD_HOST_FRAGMENTS) and not host.startswith("staging"):
            if "staging" not in str(host):
                raise CommandError(
                    f"Refusing to reset DB at host={host!r} — looks like production. "
                    "Edit PROD_HOST_FRAGMENTS in this command if you really mean it."
                )

        self.stdout.write(self.style.WARNING(
            f"\nAbout to wipe DB:\n  ENGINE: {engine}\n  HOST/NAME: {host}\n"
        ))

        if not settings.DEBUG and not opts["i_mean_it"]:
            raise CommandError(
                "DEBUG=False — pass --i-mean-it to confirm. "
                "(This is the staging-safety check; it does not bypass the prod-host refusal above.)"
            )

        if settings.DEBUG and not opts["i_mean_it"]:
            answer = input("Type the DB host/name to confirm: ").strip()
            if answer != str(host):
                raise CommandError(f"Got {answer!r}, expected {str(host)!r}. Aborting.")

        # Drop schema. Postgres + sqlite both honor `flush --no-input`'s
        # truncate-tables-in-place model, but for a *fresh* migration run we
        # need the migration history wiped too. For Postgres the cleanest
        # route is `DROP SCHEMA public CASCADE; CREATE SCHEMA public;` —
        # for sqlite, deleting the file is simpler but Django's connection
        # has it open. So: introspect the connection and drop all tables.
        self.stdout.write("Dropping all tables…")
        self._drop_all_tables()

        self.stdout.write("Running migrate from scratch…")
        call_command("migrate", verbosity=1, interactive=False)

        if not opts["no_superuser"]:
            try:
                call_command("ensure_superuser", verbosity=1)
            except Exception as exc:  # pragma: no cover - depends on env vars
                self.stdout.write(self.style.WARNING(
                    f"ensure_superuser skipped/failed: {exc}"
                ))

        self.stdout.write(self.style.SUCCESS("\nDB reset complete."))

    def _drop_all_tables(self):
        vendor = connection.vendor
        with connection.cursor() as cursor:
            if vendor == "postgresql":
                cursor.execute("DROP SCHEMA public CASCADE;")
                cursor.execute("CREATE SCHEMA public;")
                cursor.execute("GRANT ALL ON SCHEMA public TO public;")
            elif vendor == "sqlite":
                cursor.execute("PRAGMA foreign_keys = OFF;")
                cursor.execute(
                    "SELECT name FROM sqlite_master "
                    "WHERE type='table' AND name NOT LIKE 'sqlite_%'"
                )
                tables = [row[0] for row in cursor.fetchall()]
                for table in tables:
                    cursor.execute(f'DROP TABLE IF EXISTS "{table}"')
                cursor.execute("PRAGMA foreign_keys = ON;")
            else:
                raise CommandError(
                    f"reset_staging_db only knows postgresql + sqlite, got {vendor!r}"
                )
