from django.conf import settings
from django.db import models
from django.utils import timezone

from shop_management.models.base import DataRoot
from shop_management.models.data.inventory import InventoryBatch
from shop_management.models.data.organization import Warehouse
from shop_management.models.data.product import Product
from shop_management.models.data.utils import Currency


class StockAdjustment(DataRoot):
    class Kind(models.TextChoices):
        STANDARD = "STANDARD", "Standard Adjustment"
        OPENING = "OPENING", "Opening Inventory"

    class Status(models.TextChoices):
        DRAFT = "DRAFT", "Draft"
        POSTED = "POSTED", "Posted"
        VOID = "VOID", "Cancelled"

    adjustment_number = models.CharField(max_length=50, unique=True, null=True, blank=True)
    adjustment_kind = models.CharField(
        max_length=10, choices=Kind.choices, default=Kind.STANDARD
    )
    warehouse = models.ForeignKey(
        Warehouse, related_name="stock_adjustments", on_delete=models.PROTECT
    )
    adjustment_date = models.DateField(default=timezone.localdate)
    reason = models.CharField(max_length=255)
    notes = models.TextField(blank=True)
    status = models.CharField(max_length=10, choices=Status.choices, default=Status.DRAFT)
    posted_at = models.DateTimeField(null=True, blank=True)
    posted_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.PROTECT,
        related_name="stock_adjustments_posted",
    )
    voided_at = models.DateTimeField(null=True, blank=True)
    voided_by = models.ForeignKey(
        settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.PROTECT,
        related_name="stock_adjustments_voided",
    )
    void_reason = models.TextField(blank=True)

    class Meta:
        ordering = ["-adjustment_date", "-id"]

    def __str__(self):
        return self.adjustment_number or f"Draft adjustment #{self.pk}"


class StockAdjustmentItem(DataRoot):
    class Direction(models.TextChoices):
        IN = "IN", "Increase"
        OUT = "OUT", "Decrease"

    adjustment = models.ForeignKey(
        StockAdjustment, related_name="items", on_delete=models.CASCADE
    )
    product = models.ForeignKey(
        Product, related_name="stock_adjustment_items", on_delete=models.PROTECT
    )
    batch = models.ForeignKey(
        InventoryBatch, related_name="stock_adjustment_items", on_delete=models.PROTECT
    )
    direction = models.CharField(max_length=3, choices=Direction.choices)
    quantity = models.DecimalField(max_digits=18, decimal_places=4)
    unit_cost = models.DecimalField(
        max_digits=18, decimal_places=6, null=True, blank=True,
        help_text="Required for incoming adjustments; outgoing adjustments use current average cost.",
    )
    currency = models.ForeignKey(
        Currency, related_name="stock_adjustment_items", on_delete=models.PROTECT
    )
    remarks = models.TextField(blank=True)

    class Meta:
        constraints = [
            models.UniqueConstraint(
                fields=["adjustment", "product", "batch"],
                name="uniq_adjustment_product_batch",
            ),
            models.CheckConstraint(
                check=models.Q(quantity__gt=0), name="adjustment_item_quantity_positive"
            ),
            models.CheckConstraint(
                check=models.Q(unit_cost__isnull=True) | models.Q(unit_cost__gte=0),
                name="adjustment_item_cost_nonnegative",
            ),
        ]
        ordering = ["id"]

    def __str__(self):
        return f"{self.adjustment} - {self.product} - {self.direction} {self.quantity}"
