"""Hull section handler — the reference implementation.

Owns the hull stockroom behavior (price-rule inheritance, ship-type auto-listing,
stock recompute, %-price refresh) plus the back-office/storefront page context.
"""

import logging

from django.conf import settings

from ...models import AUTO_STOCK, HULL, PCT_MODES, HullListing, Shop, ShopSource
from ...tasks import TASK_PRIORITY, refresh_price_for_type
from ..base import SectionHandler, register
from .forms import EditStockroomForm, HullStockroomForm
from .stock import recompute_shop_stock, ship_type_ids_in_source

logger = logging.getLogger(__name__)


class HullSectionHandler(SectionHandler):
    section = HULL
    stockroom_form_class = HullStockroomForm
    edit_stockroom_form_class = EditStockroomForm
    manage_template = "shop/manage.html"
    featured_model = HullListing

    def manage_context(self, shop, request):
        from ...forms import AddStockroomForm
        from ...sources import source_tree
        from .forms import AddHullForm

        return {
            "listings": HullListing.objects.filter(shop=shop)
            .select_related("eve_type", "eve_type__eve_group")
            .order_by("eve_type__name"),
            "sources": shop.sources.filter(section=HULL).select_related(
                "character_audit__character"
            ),
            "add_hull_form": AddHullForm(),
            "add_stockroom_form": AddStockroomForm(owner=request.user, shop=shop),
            "source_tree": source_tree(request.user, shop),
        }

    def storefront_context(self, shop, request):
        base = HullListing.objects.filter(shop=shop).select_related(
            "eve_type", "eve_type__eve_group"
        )
        featured = list(
            base.filter(featured=True).order_by("featured_at", "eve_type__name")
        )
        grouped = list(
            base.filter(featured=False).order_by(
                "eve_type__eve_group__name", "eve_type__name"
            )
        )
        view = request.GET.get("view", "grid")
        if view not in ("grid", "table"):
            view = "grid"
        return {
            "featured_listings": featured,
            "grouped_listings": grouped,
            "view": view,
        }

    def build_order_line(self, shop, listing_id):
        listing = HullListing.objects.filter(shop=shop, pk=listing_id).first()
        if listing is None:
            return None
        return {
            "section": HULL,
            "eve_type": listing.eve_type,
            "unit_price": listing.price,
            "listing_id": listing.pk,
            "label": "",
            "available": None,  # build-to-order — no quantity cap
        }

    def _autolist_source(self, source):
        """Auto-list ship types found in `source` as HullListings, inheriting the
        source's price rule. Returns type_ids for which a NEW listing was created."""
        from eveuniverse.models import EveType

        created = []
        for type_id in ship_type_ids_in_source(source):
            try:
                EveType.objects.get_or_create_esi(id=type_id)
            except Exception:
                logger.warning("skipping unresolvable type %s for auto-list", type_id)
                continue
            _, was_created = HullListing.objects.get_or_create(
                shop=source.shop,
                eve_type_id=type_id,
                defaults={
                    "price_mode": source.price_mode,
                    "price_pct": source.price_pct,
                },
            )
            if was_created:
                created.append(type_id)
        return created

    def _enqueue_pct_refresh(self, shop, type_ids):
        if not type_ids:
            return
        pct_type_ids = (
            shop.hull_listings.filter(
                eve_type_id__in=type_ids, price_mode__in=PCT_MODES
            )
            .values_list("eve_type_id", flat=True)
            .distinct()
        )
        for type_id in pct_type_ids:
            refresh_price_for_type.apply_async(args=[type_id], priority=TASK_PRIORITY)

    def stockroom_added(self, source, cd):
        source.price_mode = cd["price_mode"]
        source.price_pct = cd.get("price_pct")
        source.save(update_fields=["price_mode", "price_pct"])
        created = self._autolist_source(source)
        recompute_shop_stock(source.shop)
        self._enqueue_pct_refresh(source.shop, created)

    def stockroom_edited(self, source, cd):
        source.price_mode = cd["price_mode"]
        source.price_pct = cd.get("price_pct")
        source.save(update_fields=["price_mode", "price_pct"])

    def stockroom_removed(self, shop):
        recompute_shop_stock(shop)

    def shops_to_recompute(self):
        from django.db.models import Q

        return (
            Shop.objects.filter(
                Q(hull_listings__stock_mode=AUTO_STOCK) | Q(sources__section=HULL)
            )
            .values_list("pk", flat=True)
            .distinct()
        )

    def enqueue_source_refresh(self):
        """Force a corptools asset pull for each character/corporation backing an
        auto-stock hull stockroom. Opt out with SHOP_REFRESH_CORPTOOLS_ASSETS=False."""
        if not getattr(settings, "SHOP_REFRESH_CORPTOOLS_ASSETS", True):
            return []
        from corptools.tasks.character.assets import update_char_assets
        from corptools.tasks.corporation import update_corp_assets

        auto = ShopSource.objects.filter(
            section=HULL, shop__hull_listings__stock_mode=AUTO_STOCK
        )
        eve_char_ids = list(
            auto.filter(character_audit__isnull=False)
            .values_list("character_audit__character__character_id", flat=True)
            .distinct()
        )
        for eve_char_id in eve_char_ids:
            update_char_assets.apply_async(
                args=[eve_char_id],
                kwargs={"force_refresh": True},
                priority=TASK_PRIORITY,
            )
        corp_ids = list(
            auto.filter(corporation_audit__isnull=False)
            .values_list("corporation_audit__corporation__corporation_id", flat=True)
            .distinct()
        )
        for corp_id in corp_ids:
            update_corp_assets.apply_async(
                args=[corp_id],
                kwargs={"force_refresh": True},
                priority=TASK_PRIORITY,
            )
        return eve_char_ids + corp_ids

    def recompute(self, shop):
        created = []
        for source in shop.sources.filter(section=HULL):
            created += self._autolist_source(source)
        recompute_shop_stock(shop)
        self._enqueue_pct_refresh(shop, created)


register(HullSectionHandler())
