"""Blueprint-copy models: the per-type listing, its ME/TE/runs variants, and the
thin ESI blueprint mirror that supplies each copy's ME/TE/runs."""

from django.db import models

from .base import FeaturedListing
from .core import Shop


class BpcListing(FeaturedListing):
    """A blueprint type offered by a shop; variants (ME/TE/runs) hang off it."""

    shop = models.ForeignKey(
        Shop, on_delete=models.CASCADE, related_name="bpc_listings"
    )
    eve_type = models.ForeignKey(
        "eveuniverse.EveType", on_delete=models.PROTECT, related_name="+"
    )
    created_at = models.DateTimeField(auto_now_add=True)

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

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

    def _visible_variants(self):
        """Prefetch-friendly: variants the shop actually offers (hidden excluded)."""
        return [v for v in self.variants.all() if not v.hidden]

    @property
    def variant_count(self) -> int:
        return len(self._visible_variants())

    @property
    def total_stock(self) -> int:
        return sum(v.stock for v in self._visible_variants())

    @property
    def total_runs(self) -> int:
        return sum(v.runs * v.stock for v in self._visible_variants())

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

        priced = [v.price for v in self._visible_variants() if v.price > 0]
        return format_isk(min(priced)) if priced else "Ask"

    @property
    def from_per_run_display(self) -> str:
        """Cheapest per-run price across visible priced variants (or "Ask")."""
        from ..formatting import format_isk

        priced = [
            v.price_per_run for v in self._visible_variants() if v.price_per_run > 0
        ]
        return f"{format_isk(min(priced))}/run" if priced else "Ask"

    @property
    def per_run_range_display(self) -> str:
        """Back-office per-run summary across visible variants.

        "20 ISK / run" (single price), "25-140 ISK / run" (a range), with
        " | ASK" appended when any variant is still unpriced. "ASK" if none priced.
        """
        from ..formatting import format_isk

        variants = self._visible_variants()
        priced = [v.price_per_run for v in variants if v.price_per_run > 0]
        has_ask = any(v.price <= 0 for v in variants)
        if not priced:
            return "ASK"
        lo, hi = min(priced), max(priced)

        def denom(n):
            return format_isk(n).replace(" ISK", "")

        core = denom(lo) if lo == hi else f"{denom(lo)}-{denom(hi)}"
        label = f"{core} ISK / run"
        return f"{label} | ASK" if has_ask else label


class BpcVariant(models.Model):
    """One (ME, TE, runs) variant of a BpcListing, with stored stock + price."""

    listing = models.ForeignKey(
        BpcListing, on_delete=models.CASCADE, related_name="variants"
    )
    me = models.PositiveSmallIntegerField()
    te = models.PositiveSmallIntegerField()
    runs = models.IntegerField()
    stock = models.PositiveIntegerField(default=0)
    price = models.PositiveBigIntegerField(default=0)  # ISK; 0 = "Ask"
    price_per_run = models.PositiveBigIntegerField(default=0)  # ISK/run; 0 = "Ask"
    hidden = models.BooleanField(
        default=False
    )  # operator hid this variant: excluded from the storefront

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["listing", "me", "te", "runs"], name="uniq_bpc_variant"
            )
        ]

    def compute_price_per_run(self) -> int:
        """Derive ISK-per-run from the fixed price and run count (0 when unpriced)."""
        if self.price <= 0 or self.runs <= 0:
            return 0
        return self.price // self.runs

    @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_per_run_display(self) -> str:
        from ..formatting import format_isk

        return "—" if self.price_per_run <= 0 else format_isk(self.price_per_run)

    @property
    def price_denom(self) -> str:
        """Abbreviated denomination for the price form, e.g. "20M" (or "Ask")."""
        from ..formatting import format_isk

        return "Ask" if self.price <= 0 else format_isk(self.price).replace(" ISK", "")


class CharacterBlueprint(models.Model):
    """Thin mirror of ESI /characters/{id}/blueprints/ (corptools lacks ME/TE/runs).

    Keyed by the EVE item_id, which equals corptools CharacterAsset.item_id — the
    stock-join key.
    """

    character = models.ForeignKey(
        "corptools.CharacterAudit", on_delete=models.CASCADE, related_name="+"
    )
    item_id = models.PositiveBigIntegerField(unique=True)
    type_id = models.PositiveIntegerField()
    me = models.PositiveSmallIntegerField()
    te = models.PositiveSmallIntegerField()
    runs = models.IntegerField()
    quantity = models.IntegerField()

    def __str__(self):
        return f"bp#{self.item_id} ({self.me}/{self.te} r{self.runs})"


class CorporationBlueprint(models.Model):
    """Thin mirror of ESI /corporations/{id}/blueprints/ (corptools lacks ME/TE/runs).

    Keyed by the EVE item_id, which equals corptools CorpAsset.item_id — the
    stock-join key.
    """

    corporation_audit = models.ForeignKey(
        "corptools.CorporationAudit", on_delete=models.CASCADE, related_name="+"
    )
    item_id = models.PositiveBigIntegerField(unique=True)
    type_id = models.PositiveIntegerField()
    me = models.PositiveSmallIntegerField()
    te = models.PositiveSmallIntegerField()
    runs = models.IntegerField()
    quantity = models.IntegerField()

    def __str__(self):
        return f"corpbp#{self.item_id} ({self.me}/{self.te} r{self.runs})"
