from django.db import models
from django.contrib.auth.models import User
from inventory.models import Product


class SavedItem(models.Model):
    """
    Represents a product saved by a user for later viewing.
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='saved_items')
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        unique_together = ('user', 'product')

    def __str__(self):
        return f"{self.user.username} saved {self.product.name}"


class ShippingMethod(models.Model):
    """
    Represents a shipping method available for orders.
    """
    name = models.CharField(max_length=100, unique=True)
    description = models.TextField(blank=True, null=True)
    cost = models.DecimalField(max_digits=10, decimal_places=2)
    is_active = models.BooleanField(default=True)

    def __str__(self):
        """
        Display name and cost (or 'Free' if the cost is 0).
        """
        return f"{self.name} - {'Free' if self.cost == 0 else f'Ksh {self.cost:.2f}'}"


class Cart(models.Model):
    """
    Represents a shopping cart for a user or guest.
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    session_key = models.CharField(max_length=40, null=True, blank=True, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        """
        String representation of the cart.
        """
        return f"{self.user.username}'s Cart" if self.user else f"Guest Cart (Session: {self.session_key})"

    def get_total_price(self):
        """
        Calculate the total price of all items in the cart.
        """
        return sum(item.get_total_price() for item in self.items.select_related('product').all())

    def get_total_items(self):
        """
        Calculate the total number of items in the cart.
        """
        return sum(item.quantity for item in self.items.all())


class CartItem(models.Model):
    """
    Represents a product added to a cart.
    """
    cart = models.ForeignKey(Cart, related_name='items', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField(default=1)

    def __str__(self):
        """
        String representation of the cart item.
        """
        return f"{self.quantity}x {self.product.name} in {self.cart}"

    def get_unit_price(self):
        """
        Get the price of the product (discount price if available, otherwise selling price).
        """
        return self.product.discount_price or self.product.selling_price

    def get_total_price(self):
        """
        Calculate the total price for this cart item.
        """
        return self.get_unit_price() * self.quantity


class ShippingAddress(models.Model):
    """
    Stores the shipping address for an order.
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    guest_email = models.EmailField(null=True, blank=True)
    address_line_1 = models.CharField(max_length=255)
    address_line_2 = models.CharField(max_length=255, blank=True, null=True)
    city = models.CharField(max_length=100)
    postal_code = models.CharField(max_length=20)
    country = models.CharField(max_length=100)

    def __str__(self):
        """
        String representation of the shipping address.
        """
        return f"{self.user.username}'s Address" if self.user else f"Guest Address ({self.guest_email})"


class Order(models.Model):
    """
    Represents an order placed by a user or guest.
    """
    user = models.ForeignKey(User, on_delete=models.CASCADE, null=True, blank=True)
    guest_email = models.EmailField(null=True, blank=True)
    shipping_address = models.ForeignKey(ShippingAddress, on_delete=models.SET_NULL, null=True)
    shipping_method = models.ForeignKey(ShippingMethod, on_delete=models.SET_NULL, null=True)
    mpesa_checkout_request_id = models.CharField(max_length=255, blank=True, null=True)
    payment_method = models.CharField(
        max_length=20,
        choices=[
            ('mpesa', 'M-Pesa'),
            ('card', 'Card Payment'),
            ('payment_on_delivery', 'Payment on Delivery'),
        ],
        default='mpesa',
    )
    mpesa_payment_status = models.CharField(
        max_length=30,
        choices=[
            ('Pending', 'Pending'),
            ('Paid', 'Paid'),
            ('Failed', 'Failed'),
            ('Payment on Delivery', 'Payment on Delivery'),
        ],
        default='Pending',
    )
    created_at = models.DateTimeField(auto_now_add=True)
    total_price = models.DecimalField(max_digits=10, decimal_places=2)
    status = models.CharField(
        max_length=20,
        choices=[
            ('Pending', 'Pending'),
            ('Processing', 'Processing'),
            ('Shipped', 'Shipped'),
            ('Delivered', 'Delivered'),
            ('Cancelled', 'Cancelled'),
        ],
        default='Pending',
    )

    def __str__(self):
        """
        String representation of the order.
        """
        return f"Order #{self.id} - {self.user.username if self.user else 'Guest'}"

    def get_total_items(self):
        """
        Calculate the total number of items in the order.
        """
        return sum(item.quantity for item in self.items.select_related('product').all())

    def calculate_total_with_shipping(self):
        """
        Calculate the total price, including shipping.
        """
        return self.total_price + (self.shipping_method.cost if self.shipping_method else 0)

    def update_status(self, new_status):
        """
        Update the status of the order.
        """
        self.status = new_status
        self.save()


class OrderItem(models.Model):
    """
    Represents a single product in an order.
    """
    order = models.ForeignKey(Order, related_name='items', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.PositiveIntegerField()
    price = models.DecimalField(max_digits=10, decimal_places=2)

    def __str__(self):
        """
        String representation of the order item.
        """
        return f"{self.quantity}x {self.product.name} in Order #{self.order.id}"

    def get_total_price(self):
        """
        Calculate the total price for this order item.
        """
        return self.price * self.quantity
