"""Hull listing model — a ship type on sale, with stored stock and a price rule."""

from decimal import ROUND_HALF_UP, Decimal

from django.db import models

from .base import (
    AUTO_STOCK,
    FIXED_PRICE,
    FIXED_STOCK,
    HULL,
    JITA_BUY_PCT,
    PCT_MODES,
    PRICE_MODE_CHOICES,
    STOCK_MODE_CHOICES,
    FeaturedListing,
    format_price_rule,
)
from .core import Shop


class HullListing(FeaturedListing):
    """A ship type listed for sale by a shop, with stored stock."""

    shop = models.ForeignKey(
        Shop, on_delete=models.CASCADE, related_name="hull_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
    stock_mode = models.CharField(
        max_length=10, choices=STOCK_MODE_CHOICES, default=AUTO_STOCK
    )
    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
    )  # e.g. 90.00; used only in pct price modes
    persist = models.BooleanField(
        default=False
    )  # keep listing when auto-stock hits 0; unchecked = auto-remove at 0
    description = models.TextField(blank=True, default="")
    created_at = models.DateTimeField(auto_now_add=True)

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

    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 (caller saves/bulk_updates). No save here.
        Keep-last-known: leaves price untouched 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:
        if self.stock_mode == FIXED_STOCK:
            return self.stock
        from ..sources import source_qty

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

    @property
    def description_html(self) -> str:
        from ..markdown import render_markdown

        return render_markdown(self.description)
