"""Module listing model — a fitting-gear type on sale, auto-stocked, priced.

Simpler than HullListing: no stock_mode / persist / build-to-order. A module is
listed only while it has stock (recompute drops it at 0).
"""

from decimal import ROUND_HALF_UP, Decimal

from django.db import models

from .base import (
    FIXED_PRICE,
    JITA_BUY_PCT,
    MODULES,
    PCT_MODES,
    PRICE_MODE_CHOICES,
    FeaturedListing,
    format_price_rule,
)
from .core import Shop


class ModuleListing(FeaturedListing):
    """A module/rig/drone/implant type listed for sale, with stored auto stock."""

    shop = models.ForeignKey(
        Shop, on_delete=models.CASCADE, related_name="module_listings"
    )
    eve_type = models.ForeignKey(
        "eveuniverse.EveType", on_delete=models.PROTECT, related_name="+"
    )
    price = models.PositiveBigIntegerField(default=0)  # ISK; 0 = "Ask"
    stock = models.PositiveIntegerField(default=0)  # stored snapshot
    price_mode = models.CharField(
        max_length=20, choices=PRICE_MODE_CHOICES, default=FIXED_PRICE
    )
    price_pct = models.DecimalField(
        max_digits=5, decimal_places=2, null=True, blank=True
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["shop", "eve_type"], name="uniq_shop_module"
            )
        ]

    def __str__(self):
        return f"{self.shop.slug}: {self.eve_type.name}"

    @property
    def price_display(self) -> str:
        from ..formatting import format_isk

        return "Ask" if self.price == 0 else format_isk(self.price)

    @property
    def price_mode_display(self) -> str:
        return format_price_rule(self.price_mode, self.price_pct, self.price)

    def apply_jita_price(self, buy, sell) -> bool:
        """Set price from Jita percentiles per this listing's pct rule. Returns True
        if price changed. Keep-last-known when the needed side is None."""
        if self.price_mode not in PCT_MODES:
            return False
        base = buy if self.price_mode == JITA_BUY_PCT else sell
        if base is None:
            return False
        new_price = int(
            (self.price_pct / Decimal(100) * Decimal(base)).to_integral_value(
                rounding=ROUND_HALF_UP
            )
        )
        if new_price == self.price:
            return False
        self.price = new_price
        return True

    def recompute_stock(self, save=True) -> int:
        """Auto stock: sum quantities across the shop's module sources."""
        from ..sources import source_qty

        sources = self.shop.sources.filter(section=MODULES)
        self.stock = sum(source_qty(s, self.eve_type) for s in sources)
        if save:
            self.save(update_fields=["stock"])
        return self.stock
