import uuid
import secrets
from datetime import datetime

from django.conf import settings
from django.db import models


class Cart(models.Model):
    """Session-based or user-based shopping cart."""

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="carts",
    )
    session_key = models.CharField(max_length=200, blank=True, default="", db_index=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-updated_at"]

    def __str__(self):
        return f"Cart {str(self.id)[:8]}"

    @property
    def total(self):
        return sum(item.subtotal for item in self.items.all())

    @property
    def item_count(self):
        return sum(item.quantity for item in self.items.all())


class CartItem(models.Model):
    """A single product entry in a cart."""

    cart = models.ForeignKey(Cart, on_delete=models.CASCADE, related_name="items")
    product = models.ForeignKey("vendors.VendorProduct", on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1)
    added_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = ["cart", "product"]

    def __str__(self):
        return f"{self.product.name} x{self.quantity}"

    @property
    def subtotal(self):
        return self.product.price * self.quantity


class Order(models.Model):
    """A completed order placed by a shopper."""

    STATUS_CHOICES = [
        ("pending", "Pending"),
        ("confirmed", "Confirmed"),
        ("processing", "Processing"),
        ("shipped", "Shipped"),
        ("delivered", "Delivered"),
        ("cancelled", "Cancelled"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    order_number = models.CharField(max_length=20, unique=True, db_index=True, blank=True, default="")
    paystack_reference = models.CharField(max_length=200, blank=True, default="", db_index=True)
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="orders",
    )
    session_key = models.CharField(max_length=200, blank=True, default="")
    customer_name = models.CharField(max_length=200)
    customer_email = models.EmailField()
    customer_phone = models.CharField(max_length=30, blank=True, default="")
    delivery_address = models.TextField()
    items_subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    delivery_total = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.order_number or str(self.id)[:8]} — {self.customer_name}"

    @staticmethod
    def _generate_order_number() -> str:
        """
        Create an order number in the format ACA-XXXX-XXXX-YY
        where X are digits and YY is 2-digit year.
        """
        year = datetime.utcnow().strftime("%y")
        block1 = f"{secrets.randbelow(10000):04d}"
        block2 = f"{secrets.randbelow(10000):04d}"
        return f"ACA-{block1}-{block2}-{year}"

    def save(self, *args, **kwargs):
        if not self.order_number:
            # Ensure uniqueness with a few attempts
            for _ in range(10):
                num = self._generate_order_number()
                if not Order.objects.filter(order_number=num).exists():
                    self.order_number = num
                    break
            if not self.order_number:
                # Fallback to UUID tail if collisions somehow persist
                self.order_number = f"ACA-{str(uuid.uuid4())[:8].upper()}-{datetime.utcnow().strftime('%y')}"
        super().save(*args, **kwargs)


class OrderItem(models.Model):
    """Snapshot of a product at time of purchase."""

    order = models.ForeignKey(Order, on_delete=models.CASCADE, related_name="items")
    vendor = models.ForeignKey(
        "vendors.Vendor", on_delete=models.SET_NULL, null=True
    )
    product = models.ForeignKey(
        "vendors.VendorProduct", on_delete=models.SET_NULL, null=True
    )
    product_name = models.CharField(max_length=300)
    product_price = models.DecimalField(max_digits=10, decimal_places=2)
    currency = models.CharField(max_length=10, default="USD")
    quantity = models.PositiveIntegerField(default=1)
    subtotal = models.DecimalField(max_digits=12, decimal_places=2)

    def __str__(self):
        return f"{self.product_name} x{self.quantity}"


class VendorOrder(models.Model):
    """
    Split order per vendor — each vendor sees only their portion of a
    multi-vendor order.
    """

    STATUS_CHOICES = Order.STATUS_CHOICES

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    order = models.ForeignKey(
        Order, on_delete=models.CASCADE, related_name="vendor_orders"
    )
    vendor = models.ForeignKey(
        "vendors.Vendor", on_delete=models.CASCADE, related_name="vendor_orders"
    )
    items_subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    delivery_fee = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return f"VendorOrder {str(self.id)[:8]} — {self.vendor.store_name}"


class PendingCheckout(models.Model):
    """
    Checkout snapshot used for Paystack pay-first flow.
    Order / VendorOrder / escrow rows are created only after payment succeeds.
    """

    STATUS_PENDING_PAYMENT = "pending_payment"
    STATUS_PAID = "paid"
    STATUS_CHOICES = [
        (STATUS_PENDING_PAYMENT, "Awaiting payment"),
        (STATUS_PAID, "Paid — order created"),
    ]

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    cart = models.ForeignKey(
        Cart,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="pending_checkouts",
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="pending_checkouts",
    )
    session_key = models.CharField(max_length=200, blank=True, default="")
    customer_name = models.CharField(max_length=200)
    customer_email = models.EmailField()
    customer_phone = models.CharField(max_length=30, blank=True, default="")
    delivery_address = models.TextField()
    items_subtotal = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    delivery_total = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2)
    lines = models.JSONField(
        help_text="List of {product_id, quantity, product_price, product_name, currency, vendor_id, line_subtotal}"
    )
    vendor_breakdown = models.JSONField(
        default=list,
        blank=True,
        help_text="List of {vendor_id, items_subtotal, delivery_fee, vendor_total}",
    )
    paystack_reference = models.CharField(max_length=200, blank=True, default="", db_index=True)
    status = models.CharField(
        max_length=30, choices=STATUS_CHOICES, default=STATUS_PENDING_PAYMENT, db_index=True
    )
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return f"PendingCheckout {str(self.id)[:8]} — {self.status}"
