"""Create/refresh a deterministic demo shop for screenshots and e2e fixtures.

Loads its catalogue (hulls / modules / BPCs / real fits + shop copy) from the
bundled ``demo_data.json`` and writes it via the ORM (no corptools sourcing).
Idempotent by slug (wipes and recreates that shop). Destructive, so it refuses to
run outside DEBUG unless ``--force`` is given; it never creates users or perms.
"""

import json
from pathlib import Path

from django.conf import settings
from django.contrib.auth import get_user_model
from django.core.management.base import BaseCommand, CommandError
from django.db import transaction
from django.utils import timezone

from shop.models import (
    BPC,
    FITTED,
    FIXED_PRICE,
    FIXED_STOCK,
    HULL,
    MODULES,
    BpcListing,
    BpcVariant,
    Buyer,
    FittedListing,
    HullListing,
    ModuleListing,
    Order,
    OrderLine,
    Shop,
)

DATA_PATH = Path(__file__).with_name("demo_data.json")
_FITTED_ITEM_BASE = 990_000_000  # synthetic item_ids for the demo fits


class Command(BaseCommand):
    help = (
        "Create/refresh a demo shop (all sections + sample orders) for screenshots/e2e."
    )

    def add_arguments(self, parser):
        parser.add_argument(
            "--user",
            required=True,
            help="Owner username (must already exist and have a main character).",
        )
        parser.add_argument("--slug", default="demo", help="Shop slug (default: demo).")
        parser.add_argument(
            "--print-session",
            action="store_true",
            dest="print_session",
            help="Print a login sessionid for the owner (e2e back-office auth).",
        )
        parser.add_argument(
            "--force",
            action="store_true",
            help="Allow the destructive wipe / --print-session outside DEBUG.",
        )

    def handle(self, *args, **options):
        if not settings.DEBUG and not options["force"]:
            raise CommandError(
                "Refusing to run outside DEBUG without --force: this wipes and "
                "recreates the demo shop."
            )
        owner = self._resolve_owner(options["user"])
        data = json.loads(DATA_PATH.read_text())
        with transaction.atomic():
            shop = self._recreate_shop(options["slug"], owner, data["shop"])
            self._seed_listings(shop, data)
            self._seed_orders(shop)
        n_h = shop.hull_listings.count()
        n_m = shop.module_listings.count()
        n_b = shop.bpc_listings.count()
        n_f = shop.fitted_listings.count()
        n_o = shop.orders.count()
        self.stdout.write(
            self.style.SUCCESS(
                f"Seeded '{shop.slug}' ({shop.name}): {n_h} hulls, {n_m} modules, "
                f"{n_b} bpc, {n_f} fitted, {n_o} orders."
            )
        )
        if options["print_session"]:
            self._print_session(owner)

    def _resolve_owner(self, username):
        user_model = get_user_model()
        try:
            user = user_model.objects.get(username=username)
        except user_model.DoesNotExist:
            raise CommandError(f"No user named '{username}'.")
        main = getattr(getattr(user, "profile", None), "main_character", None)
        if main is None:
            raise CommandError(
                f"User '{username}' has no main character; the back-office needs one."
            )
        return user

    def _recreate_shop(self, slug, owner, shop_data):
        Shop.objects.filter(slug=slug).delete()  # cascades to listings/sources/orders
        return Shop.objects.create(
            slug=slug,
            name=shop_data["name"],
            created_by=owner,
            is_published=True,
            enabled_sections=[HULL, MODULES, BPC, FITTED],
            description=shop_data["description"],
        )

    def _et(self, type_id):
        from eveuniverse.models import EveType

        obj, _ = EveType.objects.get_or_create_esi(id=type_id)
        return obj

    def _featured_at(self, featured):
        return timezone.now() if featured else None

    def _seed_listings(self, shop, data):
        for type_id, price, stock, featured in data["hulls"]:
            HullListing.objects.create(
                shop=shop,
                eve_type=self._et(type_id),
                price=price,
                stock=stock,
                stock_mode=FIXED_STOCK,
                price_mode=FIXED_PRICE,
                featured=featured,
                featured_at=self._featured_at(featured),
            )
        for type_id, price, stock, featured in data["modules"]:
            ModuleListing.objects.create(
                shop=shop,
                eve_type=self._et(type_id),
                price=price,
                stock=stock,
                price_mode=FIXED_PRICE,
                featured=featured,
                featured_at=self._featured_at(featured),
            )
        for bp in data["bpc"]:
            listing = BpcListing.objects.create(
                shop=shop,
                eve_type=self._et(bp["type_id"]),
                featured=bp["featured"],
                featured_at=self._featured_at(bp["featured"]),
            )
            for me, te, runs, stock, price in bp["variants"]:
                BpcVariant.objects.create(
                    listing=listing,
                    me=me,
                    te=te,
                    runs=runs,
                    stock=stock,
                    price=price,
                    price_per_run=price // runs if runs else 0,
                )
        for i, f in enumerate(data["fitted"], start=1):
            FittedListing.objects.create(
                shop=shop,
                eve_type=self._et(f["eve_type_id"]),
                item_id=_FITTED_ITEM_BASE + i,
                ship_name=f["ship_name"],
                price=f["price"],
                stock=1,
                featured=f["featured"],
                featured_at=self._featured_at(f["featured"]),
                fit_json=f["fit_json"],
            )

    def _seed_orders(self, shop):
        hulls = list(
            shop.hull_listings.order_by("price")[:2]
        )  # a couple of cheaper ones
        fitted = shop.fitted_listings.filter(featured=True).first()

        # Buyers are global (not cascade-deleted with the shop), so get_or_create keeps
        # the command idempotent across re-runs.
        buyer_a, _ = Buyer.objects.get_or_create(
            character_id=980_000_001,
            defaults={
                "character_name": "Test Buyer Alpha",
                "discord_handle": "testbuyer",
            },
        )
        buyer_b, _ = Buyer.objects.get_or_create(
            character_id=980_000_002,
            defaults={"character_name": "Demo Capsuleer"},
        )

        order1 = Order.objects.create(
            shop=shop,
            buyer=buyer_a,
            status=Order.PENDING,
            additional_info="Can you contract these to Jita 4-4? Cheers.",
        )
        for h in hulls:
            OrderLine.objects.create(
                order=order1,
                section=HULL,
                eve_type=h.eve_type,
                quantity=1,
                unit_price=h.price,
                listing_id=h.pk,
                label="",
            )

        order2 = Order.objects.create(
            shop=shop,
            buyer=buyer_b,
            status=Order.ACCEPTED,
            additional_info="",
        )
        if fitted is not None:
            OrderLine.objects.create(
                order=order2,
                section=FITTED,
                eve_type=fitted.eve_type,
                quantity=1,
                unit_price=fitted.price,
                listing_id=fitted.pk,
                label=fitted.ship_name[:100],
                fit_json=fitted.fit_json,
            )

    def _print_session(self, owner):
        from importlib import import_module

        from django.contrib.auth import (
            BACKEND_SESSION_KEY,
            HASH_SESSION_KEY,
            SESSION_KEY,
        )

        engine = import_module(settings.SESSION_ENGINE)
        session = engine.SessionStore()
        session[SESSION_KEY] = str(owner.pk)
        session[BACKEND_SESSION_KEY] = "django.contrib.auth.backends.ModelBackend"
        session[HASH_SESSION_KEY] = owner.get_session_auth_hash()
        session.save()
        self.stdout.write(
            self.style.SUCCESS(
                f"Owner session ({settings.SESSION_COOKIE_NAME}): {session.session_key}"
            )
        )
