"""Immutable job demand and explicit reservation history."""
from django.conf import settings
from django.db import models
from django.utils import timezone
from .models import InventoryRecord


class PartsRequest(InventoryRecord):
    company = models.ForeignKey("organization.Company", on_delete=models.PROTECT)
    service_case = models.ForeignKey("service.ServiceCase", on_delete=models.PROTECT)
    requester = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    requested_at = models.DateTimeField(default=timezone.now, editable=False)
    note = models.TextField(blank=True, max_length=2000)
    status = models.CharField(max_length=16, default="REQUESTED", choices=[(x, x.title()) for x in ("REQUESTED", "APPROVED", "CANCELLED", "REJECTED", "FULFILLED")])
    decided_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.PROTECT, related_name="+")
    decided_at = models.DateTimeField(null=True, blank=True)
    reason = models.CharField(max_length=500, blank=True)

    class Meta:
        permissions = [("request_parts", "Request parts for a service job"), ("approve_parts", "Approve or reject job parts requests"), ("reserve_parts", "Reserve or release job parts stock")]
        constraints = [
            models.CheckConstraint(condition=models.Q(status__in=["REQUESTED", "APPROVED", "CANCELLED", "REJECTED", "FULFILLED"]), name="inventory_request_status"),
            models.CheckConstraint(condition=(models.Q(status="REQUESTED", decided_at=None, decided_by=None) | (~models.Q(status="REQUESTED") & models.Q(decided_at__isnull=False, decided_by__isnull=False))), name="inventory_request_decision"),
            models.UniqueConstraint(fields=["id", "company"], name="inventory_request_owner"),
        ]


class PartsRequestLine(InventoryRecord):
    request = models.ForeignKey(PartsRequest, on_delete=models.PROTECT, related_name="lines")
    spare_part = models.ForeignKey("parts.SparePart", on_delete=models.PROTECT)
    quantity = models.PositiveIntegerField()

    class Meta:
        constraints = [models.UniqueConstraint(fields=["request", "spare_part"], name="inventory_request_part_unique"), models.CheckConstraint(condition=models.Q(quantity__gte=1, quantity__lte=1000000000), name="inventory_request_qty")]


class PartsRequestEvent(InventoryRecord):
    request = models.ForeignKey(PartsRequest, on_delete=models.PROTECT, related_name="events")
    actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    status = models.CharField(max_length=16, choices=PartsRequest._meta.get_field("status").choices)
    reason = models.CharField(max_length=500, blank=True)

    class Meta:
        constraints = [models.CheckConstraint(condition=models.Q(status__in=["REQUESTED", "APPROVED", "CANCELLED", "REJECTED", "FULFILLED"]), name="inventory_request_event_status")]


class StockReservation(InventoryRecord):
    company = models.ForeignKey("organization.Company", on_delete=models.PROTECT)
    service_case = models.ForeignKey("service.ServiceCase", on_delete=models.PROTECT)
    line = models.ForeignKey(PartsRequestLine, on_delete=models.PROTECT, related_name="reservations")
    spare_part = models.ForeignKey("parts.SparePart", on_delete=models.PROTECT)
    location = models.ForeignKey("inventory.InventoryLocation", on_delete=models.PROTECT)
    quantity = models.PositiveIntegerField()
    reserved_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name="+")
    reserved_at = models.DateTimeField(default=timezone.now, editable=False)
    status = models.CharField(max_length=16, default="ACTIVE", choices=[("ACTIVE", "Active"), ("RELEASED", "Released"), ("ISSUED", "Issued")])
    ended_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.PROTECT, related_name="+")
    ended_at = models.DateTimeField(null=True, blank=True)
    reason = models.CharField(max_length=500, blank=True)

    class Meta:
        indexes = [models.Index(fields=["location", "spare_part", "status"], name="inventory_reserve_position")]
        constraints = [
            models.CheckConstraint(condition=models.Q(quantity__gte=1, quantity__lte=1000000000), name="inventory_reserve_qty"),
            models.CheckConstraint(condition=models.Q(status__in=["ACTIVE", "RELEASED", "ISSUED"]), name="inventory_reserve_status"),
            models.CheckConstraint(condition=(models.Q(status="ACTIVE", ended_at=None, ended_by=None) | models.Q(status__in=["RELEASED", "ISSUED"], ended_at__isnull=False, ended_by__isnull=False)), name="inventory_reserve_end"),
            models.CheckConstraint(condition=models.Q(ended_at=None) | models.Q(ended_at__gte=models.F("reserved_at")), name="inventory_reserve_time"),
        ]


class ReservationUnit(InventoryRecord):
    reservation = models.ForeignKey(StockReservation, on_delete=models.PROTECT, related_name="units")
    unit = models.ForeignKey("inventory.SerializedStockUnit", on_delete=models.PROTECT)
    is_active = models.BooleanField(default=True)

    class Meta:
        constraints = [models.UniqueConstraint(fields=["reservation", "unit"], name="inventory_reservation_unit_unique"), models.UniqueConstraint(fields=["unit"], condition=models.Q(is_active=True), name="inventory_one_active_unit_reservation")]
