"""Final billing snapshots and retained consumption allocation evidence."""
from django.conf import settings
from django.db import models
from .models import Record, amount


class InvoiceSequence(models.Model):
    service_center = models.OneToOneField("organization.ServiceCenter", on_delete=models.PROTECT, primary_key=True)
    next_value = models.PositiveBigIntegerField(default=1)

    class Meta:
        constraints = [models.CheckConstraint(condition=models.Q(next_value__gte=1), name="invoice_sequence_positive")]


class ServiceInvoice(Record):
    service_case = models.OneToOneField("service.ServiceCase", on_delete=models.PROTECT, related_name="invoice")
    service_center = models.ForeignKey("organization.ServiceCenter", on_delete=models.PROTECT)
    number = models.CharField(max_length=22)
    status = models.CharField(max_length=9, choices=[("DRAFT", "Draft"), ("FINALIZED", "Finalized")], default="DRAFT")
    quotation = models.ForeignKey("commercial.ServiceQuotation", on_delete=models.PROTECT)
    currency = models.CharField(max_length=3)
    generation = models.PositiveIntegerField(default=1)
    subtotal = amount()
    discount_total = amount()
    tax_total = amount()
    grand_total = amount()
    customer_pay_total = amount()
    warranty_covered_total = amount()
    company_covered_total = amount()
    context_snapshot = models.JSONField(default=dict, blank=True)
    note = models.TextField(max_length=4000, blank=True)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT, related_name="+")
    finalized_by = models.ForeignKey(settings.AUTH_USER_MODEL, null=True, blank=True, on_delete=models.PROTECT, related_name="+")
    finalized_at = models.DateTimeField(null=True, blank=True)

    class Meta(Record.Meta):
        permissions = [("manage_serviceinvoice", "Prepare and reconcile service invoices"),
                       ("finalize_serviceinvoice", "Finalize immutable service invoices")]
        constraints = [
            models.UniqueConstraint(fields=("service_center", "number"), name="invoice_number_unique"),
            models.CheckConstraint(condition=models.Q(number__regex=r"^INV-[0-9]{8,18}$"), name="invoice_number_format"),
            models.CheckConstraint(condition=models.Q(currency__regex=r"^[A-Z]{3}$", generation__gte=1), name="invoice_currency_generation"),
            models.CheckConstraint(condition=(models.Q(status="DRAFT", finalized_at=None, finalized_by=None) |
                models.Q(status="FINALIZED", finalized_at__isnull=False, finalized_by__isnull=False)), name="invoice_finalization_coherent"),
            models.CheckConstraint(condition=models.Q(subtotal__gte=0, discount_total__gte=0, tax_total__gte=0,
                grand_total__gte=0, customer_pay_total__gte=0, warranty_covered_total__gte=0, company_covered_total__gte=0,
                discount_total__lte=models.F("subtotal"), grand_total=models.F("subtotal")-models.F("discount_total")+models.F("tax_total"),
                grand_total__exact=models.F("customer_pay_total")+models.F("warranty_covered_total")+models.F("company_covered_total")), name="invoice_totals_coherent"),
        ]

    def __str__(self):
        return self.number


class InvoiceLine(Record):
    invoice = models.ForeignKey(ServiceInvoice, on_delete=models.PROTECT, related_name="lines")
    quotation_line = models.ForeignKey("commercial.QuotationLine", on_delete=models.PROTECT)
    generation = models.PositiveIntegerField()
    is_active = models.BooleanField(default=True)
    kind = models.CharField(max_length=7)
    responsibility = models.CharField(max_length=8)
    description = models.CharField(max_length=500)
    part_code = models.CharField(max_length=128, blank=True)
    part_name = models.CharField(max_length=500, blank=True)
    quantity = models.PositiveIntegerField()
    unit_price = amount()
    subtotal = amount()
    discount = amount()
    additional_discount = amount()
    taxable_amount = amount()
    tax_rate = models.DecimalField(max_digits=5, decimal_places=2)
    tax_label = models.CharField(max_length=100, blank=True)
    tax = amount()
    total = amount()
    customer_pay = amount()
    warranty_covered = amount()
    company_covered = amount()
    confirmed_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    confirmation_note = models.TextField(max_length=2000, blank=True)

    class Meta(Record.Meta):
        constraints = [
            models.UniqueConstraint(fields=("invoice", "quotation_line"), condition=models.Q(is_active=True), name="invoice_active_quote_line"),
            models.CheckConstraint(condition=models.Q(kind__in=["PART", "LABOR", "SERVICE"], responsibility__in=["CUSTOMER", "WARRANTY", "COMPANY"], generation__gte=1), name="invoice_line_types"),
            models.CheckConstraint(condition=models.Q(quantity__gte=1, quantity__lte=1000000, unit_price__gte=0, discount__gte=0,
                additional_discount__gte=0, additional_discount__lte=models.F("discount"), discount__lte=models.F("subtotal"),
                subtotal=models.F("quantity")*models.F("unit_price"), taxable_amount=models.F("subtotal")-models.F("discount"),
                tax_rate__gte=0, tax_rate__lte=100, tax__gte=0, total=models.F("taxable_amount")+models.F("tax"),
                customer_pay__gte=0, warranty_covered__gte=0, company_covered__gte=0,
                total__exact=models.F("customer_pay")+models.F("warranty_covered")+models.F("company_covered")), name="invoice_line_money"),
            models.CheckConstraint(condition=(models.Q(responsibility="CUSTOMER", customer_pay=models.F("total"), warranty_covered=0, company_covered=0) |
                models.Q(responsibility="WARRANTY", warranty_covered=models.F("total"), customer_pay=0, company_covered=0) |
                models.Q(responsibility="COMPANY", company_covered=models.F("total"), customer_pay=0, warranty_covered=0)), name="invoice_line_payer"),
        ]


class InvoiceAllocation(Record):
    line = models.ForeignKey(InvoiceLine, on_delete=models.PROTECT, related_name="allocations")
    consumption = models.ForeignKey("inventory.PartsDisposition", on_delete=models.PROTECT)
    quantity = models.PositiveIntegerField()
    mode = models.CharField(max_length=6, choices=[("AUTO", "Automatic"), ("MANUAL", "Manual")])
    actor = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.PROTECT)
    reason = models.TextField(max_length=2000, blank=True)

    class Meta(Record.Meta):
        constraints = [models.UniqueConstraint(fields=("line", "consumption"), name="invoice_allocation_source_unique"),
            models.CheckConstraint(condition=models.Q(quantity__gte=1, quantity__lte=1000000), name="invoice_allocation_quantity"),
            models.CheckConstraint(condition=(models.Q(mode="AUTO") | (models.Q(mode="MANUAL") & ~models.Q(reason=""))), name="invoice_allocation_mode")]
