from django.db import models
from django.conf import settings
from django.utils import timezone
import secrets
import time
from apps.core.uploads import tenant_upload_path


def uuid7() -> str:
    """Generate a UUID v7 (time-ordered UUID)."""
    nanoseconds = time.time_ns()
    uuid_int = (nanoseconds << 16) | secrets.randbits(48)
    return f"{uuid_int:032x}"


_ROMAN_MONTHS = {
    1: "I", 2: "II", 3: "III", 4: "IV", 5: "V", 6: "VI",
    7: "VII", 8: "VIII", 9: "IX", 10: "X", 11: "XI", 12: "XII",
}


class Asset(models.Model):
    """Asset inventory."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="assets_scoped")
    name = models.CharField(max_length=255)
    asset_tag = models.CharField(max_length=100)
    category = models.ForeignKey("AssetCategory", on_delete=models.SET_NULL, null=True, related_name="assets")
    serial_number = models.CharField(max_length=100, blank=True)
    status = models.CharField(max_length=20, choices=[
        ("available", "Available"),
        ("assigned", "Assigned"),
        ("maintenance", "Maintenance"),
        ("retired", "Retired"),
        ("lost", "Lost"),
    ], default="available")
    location = models.ForeignKey("AssetLocation", on_delete=models.SET_NULL, null=True, blank=True, related_name="assets")
    vendor = models.ForeignKey("Vendor", on_delete=models.SET_NULL, null=True, blank=True, related_name="assets")
    purchase_order = models.ForeignKey(
        "procurements.PurchaseOrder",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="assets",
    )
    goods_receipt = models.ForeignKey(
        "procurements.GoodsReceipt",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="assets",
    )
    purchase_date = models.DateField(null=True, blank=True)
    purchase_price = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    warranty_expiry = models.DateField(null=True, blank=True)
    description = models.TextField(blank=True)
    image = models.ImageField(upload_to=tenant_upload_path("assets"), blank=True, null=True)
    specifications = models.JSONField(default=dict)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "assets"
        ordering = ["asset_tag"]
        constraints = [models.UniqueConstraint(fields=["organization", "asset_tag"], name="unique_asset_tag_per_org")]

    def __str__(self):
        return f"{self.asset_tag} - {self.name}"


class AssetCategory(models.Model):
    """Asset categories."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="asset_categories")
    slug = models.SlugField(max_length=100, blank=True, null=True)
    name = models.CharField(max_length=100)
    description = models.TextField(blank=True)
    depreciation_rate = models.DecimalField(max_digits=5, decimal_places=2, null=True, blank=True)

    class Meta:
        db_table = "asset_categories"
        ordering = ["name"]
        verbose_name_plural = "Asset Categories"
        constraints = [
            models.UniqueConstraint(fields=["organization", "name"], name="unique_asset_category_name_per_org"),
            models.UniqueConstraint(fields=["organization", "slug"], name="unique_asset_category_slug_per_org"),
        ]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug and self.name:
            self.slug = self.name.lower().replace(" ", "-")
        super().save(*args, **kwargs)


class AssetLocation(models.Model):
    """Physical locations for assets."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="asset_locations")
    slug = models.SlugField(max_length=255, blank=True, null=True)
    name = models.CharField(max_length=255)
    address = models.TextField(blank=True)
    contact_person = models.CharField(max_length=100, blank=True)
    contact_phone = models.CharField(max_length=20, blank=True)

    class Meta:
        db_table = "asset_locations"
        ordering = ["name"]
        constraints = [models.UniqueConstraint(fields=["organization", "slug"], name="unique_asset_location_slug_per_org")]

    def __str__(self):
        return self.name

    def save(self, *args, **kwargs):
        if not self.slug and self.name:
            self.slug = self.name.lower().replace(" ", "-")
        super().save(*args, **kwargs)


class AssetAssignment(models.Model):
    """Asset assignment to employees."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, related_name="assignments")
    employee = models.ForeignKey("hr.Employee", on_delete=models.CASCADE, related_name="asset_assignments")
    assigned_date = models.DateField()
    returned_date = models.DateField(null=True, blank=True)
    status = models.CharField(max_length=20, choices=[
        ("assigned", "Assigned"),
        ("returned", "Returned"),
    ], default="assigned")
    condition = models.CharField(max_length=100, blank=True)
    notes = models.TextField(blank=True)

    class Meta:
        db_table = "asset_assignments"
        ordering = ["-assigned_date"]

    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)
        new_status = "assigned" if self.status == "assigned" else "available"
        if self.asset.status != new_status:
            self.asset.status = new_status
            self.asset.save(update_fields=["status"])


class Maintenance(models.Model):
    """Asset maintenance records."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, related_name="maintenance_records")
    title = models.CharField(max_length=255)
    description = models.TextField()
    status = models.CharField(max_length=20, choices=[
        ("scheduled", "Scheduled"),
        ("in_progress", "In Progress"),
        ("completed", "Completed"),
        ("cancelled", "Cancelled"),
    ], default="scheduled")
    scheduled_date = models.DateField()
    completed_date = models.DateField(null=True, blank=True)
    cost = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    vendor = models.CharField(max_length=255, blank=True)
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "maintenance"
        ordering = ["-scheduled_date"]


class Procurement(models.Model):
    """Standalone asset-procurement request tracker.

    Distinct from the full procurements app flow (Requisition → Approval →
    PurchaseOrder → GoodsReceipt → Asset). This is the lightweight single-record
    "I need to buy this asset" tracker served at /api/procurements/ and used by
    the asset-management/procurements page. Do not merge or delete — it backs a
    live screen and has its own number sequence and status enum.
    """
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="procurements_scoped")
    number = models.CharField(max_length=40, blank=True)
    title = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    status = models.CharField(max_length=20, choices=[
        ("draft", "Draft"),
        ("pending_approval", "Pending Approval"),
        ("approved", "Approved"),
        ("ordered", "Ordered"),
        ("received", "Received"),
        ("cancelled", "Cancelled"),
    ], default="draft")
    requested_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="procurements")
    category = models.CharField(max_length=100, blank=True)
    quantity = models.IntegerField(default=1)
    estimated_cost = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    actual_cost = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    vendor = models.ForeignKey("Vendor", on_delete=models.SET_NULL, null=True, blank=True, related_name="procurements")
    asset = models.ForeignKey(
        "Asset", on_delete=models.SET_NULL, null=True, blank=True, related_name="procurements",
        help_text="Asset this procurement request is for, if any.",
    )
    items = models.JSONField(default=list, blank=True)
    delivery_date = models.DateField(null=True, blank=True)
    # Set when this lite tracker is promoted into the full procurement chain.
    # One-way link: a promoted Procurement points at the Requisition it spawned.
    requisition = models.ForeignKey(
        "procurements.Requisition",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="source_procurements",
    )
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "procurements"
        ordering = ["-created_at"]
        constraints = [models.UniqueConstraint(fields=["organization", "number"], name="unique_procurement_number_per_org")]

    def save(self, *args, **kwargs):
        if not self.number:
            now = timezone.now()
            month = _ROMAN_MONTHS[now.month]
            year = now.year
            # Derive from the highest existing sequence, not count() — gaps from
            # deleted rows would otherwise reuse a taken number and collide.
            # Scoped per-org so each org's sequence starts fresh and can't
            # collide with (or skip ahead based on) another org's rows.
            suffix = f"/{month}/{year}"
            existing = Procurement.objects.filter(organization=self.organization, number__endswith=suffix).values_list("number", flat=True)
            max_seq = 0
            for num in existing:
                try:
                    max_seq = max(max_seq, int(num.split("-")[1].split("/")[0]))
                except (IndexError, ValueError):
                    continue
            self.number = f"P-{max_seq + 1:04d}{suffix}"
        super().save(*args, **kwargs)


class AssetTicket(models.Model):
    """Support tickets for assets."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="asset_tickets")
    title = models.CharField(max_length=255)
    description = models.TextField(blank=True)
    priority = models.CharField(max_length=20, choices=[
        ("low", "Low"),
        ("medium", "Medium"),
        ("high", "High"),
        ("critical", "Critical"),
    ], default="medium")
    status = models.CharField(max_length=20, choices=[
        ("open", "Open"),
        ("in_progress", "In Progress"),
        ("resolved", "Resolved"),
        ("closed", "Closed"),
    ], default="open")
    asset = models.ForeignKey(Asset, on_delete=models.SET_NULL, null=True, blank=True, related_name="tickets")
    reported_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="asset_reported_tickets")
    assigned_to = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="asset_assigned_tickets")
    resolved_at = models.DateTimeField(null=True, blank=True)
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "asset_tickets"
        ordering = ["-created_at"]

    def __str__(self):
        return self.title


class Vendor(models.Model):
    """Vendor/supplier records."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="vendors")
    name = models.CharField(max_length=255)
    contact_person = models.CharField(max_length=100, blank=True)
    email = models.EmailField(blank=True)
    phone = models.CharField(max_length=20, blank=True)
    address = models.TextField(blank=True)
    tax_id = models.CharField(max_length=50, blank=True)
    bank_details = models.JSONField(default=dict)
    status = models.CharField(max_length=20, choices=[("pending", "Pending Verification"), ("active", "Active"), ("suspended", "Suspended"), ("blacklisted", "Blacklisted")], default="pending", db_index=True)
    risk_level = models.CharField(max_length=20, choices=[("low", "Low"), ("medium", "Medium"), ("high", "High")], default="low")
    tax_verified_at = models.DateTimeField(null=True, blank=True)
    tax_verified_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="tax_verified_vendors")
    bank_verified_at = models.DateTimeField(null=True, blank=True)
    bank_verified_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, null=True, blank=True, related_name="bank_verified_vendors")
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "vendors"
        ordering = ["name"]

    def __str__(self):
        return self.name

class AssetDocument(models.Model):
    """Documents attached to an asset — manual, warranty/guarantee card, invoice copy, etc."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    asset = models.ForeignKey(Asset, on_delete=models.CASCADE, related_name="documents")
    title = models.CharField(max_length=255)
    doc_type = models.CharField(max_length=20, choices=[
        ("manual", "Manual"),
        ("warranty", "Guarantee / Warranty Card"),
        ("invoice", "Invoice"),
        ("receipt", "Receipt"),
        ("other", "Other"),
    ], default="other")
    file = models.FileField(upload_to=tenant_upload_path("asset-documents"))
    notes = models.TextField(blank=True)
    uploaded_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True,
        related_name="uploaded_asset_documents",
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "asset_documents"
        ordering = ["-created_at"]

    def __str__(self):
        return self.title


# ──────────────────────────────────────────────────────────────────────────
# Non-asset procured items — things you buy and hold but that aren't durable
# inventory assets: licenses/subscriptions, consumable stock, and rentals.
# Each can be sourced from a procurement PurchaseOrder / GoodsReceipt, mirroring
# the Asset FKs so a goods receipt can be split into the right record type.
# ──────────────────────────────────────────────────────────────────────────


class License(models.Model):
    """Software licenses & subscriptions (M365, support contracts, SaaS seats)."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="licenses_scoped")
    name = models.CharField(max_length=255)
    vendor = models.ForeignKey("Vendor", on_delete=models.SET_NULL, null=True, blank=True, related_name="licenses")
    license_key = models.CharField(max_length=255, blank=True)
    seats = models.PositiveIntegerField(default=1)
    cost_per_period = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    period = models.CharField(max_length=20, choices=[
        ("monthly", "Monthly"),
        ("quarterly", "Quarterly"),
        ("annual", "Annual"),
        ("perpetual", "Perpetual"),
    ], default="annual")
    start_date = models.DateField(null=True, blank=True)
    renewal_date = models.DateField(null=True, blank=True, db_index=True)
    auto_renew = models.BooleanField(default=False)
    status = models.CharField(max_length=20, choices=[
        ("active", "Active"),
        ("expiring", "Expiring"),
        ("expired", "Expired"),
        ("cancelled", "Cancelled"),
    ], default="active")
    procurement = models.ForeignKey(
        "Procurement", on_delete=models.SET_NULL, null=True, blank=True, related_name="licenses",
        help_text="Request/approval record for subscribing to or renewing this license.",
    )
    purchase_order = models.ForeignKey(
        "procurements.PurchaseOrder", on_delete=models.SET_NULL, null=True, blank=True, related_name="licenses",
    )
    goods_receipt = models.ForeignKey(
        "procurements.GoodsReceipt", on_delete=models.SET_NULL, null=True, blank=True, related_name="licenses",
    )
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "licenses"
        ordering = ["renewal_date", "name"]
        indexes = [models.Index(fields=["status", "renewal_date"])]

    def __str__(self):
        return f"{self.name} ({self.seats} seats)"

    @property
    def assigned_seats(self):
        return self.seat_assignments.filter(status="assigned").count()

    @property
    def available_seats(self):
        return max(0, self.seats - self.assigned_seats)


class LicenseSeatAssignment(models.Model):
    """A license seat assigned to an employee — deducts from License.seats."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    license = models.ForeignKey(License, on_delete=models.CASCADE, related_name="seat_assignments")
    employee = models.ForeignKey("hr.Employee", on_delete=models.CASCADE, related_name="license_seat_assignments")
    assigned_date = models.DateField()
    returned_date = models.DateField(null=True, blank=True)
    status = models.CharField(max_length=20, choices=[
        ("assigned", "Assigned"),
        ("returned", "Returned"),
    ], default="assigned")
    notes = models.TextField(blank=True)

    class Meta:
        db_table = "license_seat_assignments"
        ordering = ["-assigned_date"]


class Rental(models.Model):
    """Rented equipment held for a fixed term — return tracked, not owned."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="rentals_scoped")
    name = models.CharField(max_length=255)
    vendor = models.ForeignKey("Vendor", on_delete=models.SET_NULL, null=True, blank=True, related_name="rentals")
    quantity = models.PositiveIntegerField(default=1)
    location = models.ForeignKey("AssetLocation", on_delete=models.SET_NULL, null=True, blank=True, related_name="rentals")
    rental_cost = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    deposit = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    start_date = models.DateField(null=True, blank=True)
    return_date = models.DateField(null=True, blank=True, db_index=True)
    returned_at = models.DateField(null=True, blank=True)
    returned_condition = models.CharField(max_length=20, choices=[
        ("good", "Good"),
        ("damaged", "Damaged"),
        ("lost", "Lost"),
    ], blank=True)
    status = models.CharField(max_length=20, choices=[
        ("active", "Active"),
        ("overdue", "Overdue"),
        ("returned", "Returned"),
    ], default="active")
    procurement = models.ForeignKey(
        "Procurement", on_delete=models.SET_NULL, null=True, blank=True, related_name="rentals",
        help_text="Request/approval record for renting this equipment.",
    )
    purchase_order = models.ForeignKey(
        "procurements.PurchaseOrder", on_delete=models.SET_NULL, null=True, blank=True, related_name="rentals",
    )
    goods_receipt = models.ForeignKey(
        "procurements.GoodsReceipt", on_delete=models.SET_NULL, null=True, blank=True, related_name="rentals",
    )
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "rentals"
        ordering = ["return_date", "name"]
        indexes = [models.Index(fields=["status", "return_date"])]

    def __str__(self):
        return f"{self.name} x{self.quantity}"


class StockItem(models.Model):
    """A consumable catalog item (paper, toner, pantry). Stock held per location."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    organization = models.ForeignKey("companies.Organization", on_delete=models.CASCADE, related_name="stock_items_scoped")
    name = models.CharField(max_length=255)
    sku = models.CharField(max_length=100, blank=True)
    category = models.ForeignKey("AssetCategory", on_delete=models.SET_NULL, null=True, blank=True, related_name="stock_items")
    unit = models.CharField(max_length=30, default="unit")
    reorder_point = models.PositiveIntegerField(default=0)
    unit_cost = models.DecimalField(max_digits=12, decimal_places=2, null=True, blank=True)
    vendor = models.ForeignKey("Vendor", on_delete=models.SET_NULL, null=True, blank=True, related_name="stock_items")
    notes = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "stock_items"
        ordering = ["name"]
        constraints = [models.UniqueConstraint(fields=["organization", "sku"], name="unique_stock_item_sku_per_org")]

    def __str__(self):
        return self.name

    @property
    def total_quantity(self):
        return sum((level.quantity for level in self.levels.all()), 0)


class StockLevel(models.Model):
    """On-hand quantity of a StockItem at one location. Derived from movements."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    item = models.ForeignKey(StockItem, on_delete=models.CASCADE, related_name="levels")
    location = models.ForeignKey("AssetLocation", on_delete=models.CASCADE, related_name="stock_levels")
    quantity = models.IntegerField(default=0)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "stock_levels"
        ordering = ["item__name"]
        constraints = [
            models.UniqueConstraint(fields=["item", "location"], name="uniq_stock_item_location"),
        ]

    def __str__(self):
        return f"{self.item.name} @ {self.location_id}: {self.quantity}"


class StockMovement(models.Model):
    """Immutable stock ledger entry. Each in/out/adjust/transfer mutates a StockLevel."""
    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    item = models.ForeignKey(StockItem, on_delete=models.CASCADE, related_name="movements")
    location = models.ForeignKey("AssetLocation", on_delete=models.CASCADE, related_name="stock_movements")
    movement_type = models.CharField(max_length=20, choices=[
        ("in", "Stock In"),
        ("out", "Stock Out"),
        ("adjust", "Adjustment"),
        ("transfer", "Transfer"),
    ])
    quantity = models.IntegerField(help_text="Positive for in/transfer-in, negative for out.")
    unit_cost = models.DecimalField(
        max_digits=12, decimal_places=2, null=True, blank=True,
        help_text="Cost per unit for 'in' movements. Recomputes StockItem.unit_cost as a weighted average.",
    )
    reason = models.CharField(max_length=255, blank=True)
    goods_receipt = models.ForeignKey(
        "procurements.GoodsReceipt", on_delete=models.SET_NULL, null=True, blank=True, related_name="stock_movements",
    )
    performed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True, related_name="stock_movements")
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "stock_movements"
        ordering = ["-created_at"]
        indexes = [models.Index(fields=["item", "location", "-created_at"])]

    def __str__(self):
        return f"{self.movement_type} {self.quantity} {self.item.name}"

    def apply(self):
        """Upsert the matching StockLevel by this movement's signed quantity.

        For 'in' movements with a unit_cost, also recomputes the item's
        unit_cost as a weighted average across existing on-hand quantity and
        the incoming quantity/cost.
        """
        level, _ = StockLevel.objects.get_or_create(item=self.item, location=self.location)
        old_qty = level.quantity or 0
        level.quantity = old_qty + self.quantity
        level.save(update_fields=["quantity", "updated_at"])

        if self.movement_type == "in" and self.unit_cost is not None and self.quantity > 0:
            old_cost = self.item.unit_cost or 0
            old_total_qty = self.item.total_quantity - self.quantity  # pre-movement on-hand across all locations
            if old_total_qty > 0:
                new_cost = (old_total_qty * old_cost + self.quantity * self.unit_cost) / (old_total_qty + self.quantity)
            else:
                new_cost = self.unit_cost
            self.item.unit_cost = new_cost
            self.item.save(update_fields=["unit_cost", "updated_at"])
        return level


class SellableItem(models.Model):
    """A StockItem offered for sale to the public: a book or an accessory.

    Wraps StockItem (one-to-one) rather than extending it directly, since
    StockItem also covers internal consumables (paper, toner) that are never
    sold. Books link back to the originating Publication; accessories don't.
    """
    CATEGORY_CHOICES = [("book", "Book"), ("accessory", "Accessory")]

    id = models.UUIDField(primary_key=True, default=uuid7, editable=False)
    stock_item = models.OneToOneField(StockItem, on_delete=models.CASCADE, related_name="sellable")
    category = models.CharField(max_length=20, choices=CATEGORY_CHOICES)
    publication = models.ForeignKey(
        "publications.Publication", on_delete=models.SET_NULL, null=True, blank=True,
        related_name="sellable_items", help_text="Set only when category=book.",
    )
    sale_price = models.DecimalField(max_digits=14, decimal_places=2)
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        db_table = "sellable_items"
        ordering = ["-created_at"]

    def __str__(self):
        return self.stock_item.name
