from django.db import models
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import transaction
from decimal import Decimal

from django.utils import timezone
from django.utils.timezone import now
from customers.models import Customer
from inventory.models import Product, Batch
import logging


logger = logging.getLogger(__name__)


class Sale(models.Model):
    PAYMENT_METHOD_CHOICES = [
        ('cash', 'Cash'),
        ('mpesa', 'M-Pesa'),
        ('credit', 'Credit'),
        ('cheque', 'Cheque'),
    ]

    # Schema separation provides tenant isolation - no tenant field needed
    
    # Core Fields
    customer = models.ForeignKey(Customer, null=True, blank=True, on_delete=models.SET_NULL)
    total_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    payment_method = models.CharField(max_length=10, choices=PAYMENT_METHOD_CHOICES)
    sale_date = models.DateTimeField(default=now, db_index=True)
    is_complete = models.BooleanField(default=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    # Cash/M-Pesa Fields
    cash_given = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    change_due = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    mpesa_reference = models.CharField(max_length=255, null=True, blank=True)

    # Credit Fields
    credit_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    credit_paid_date = models.DateField(null=True, blank=True)

    # Cheque Fields
    cheque_number = models.CharField(max_length=50, null=True, blank=True)
    cheque_date = models.DateField(null=True, blank=True)
    cheque_cleared = models.BooleanField(default=False)

    class Meta:
        ordering = ['-sale_date']

    def __str__(self):
        return f"Sale #{self.id} - {self.total_amount} ({self.payment_method})"

    def clean(self):
        """Validation for payment-specific fields"""
        if self.payment_method == 'cash' and not self.cash_given:
            raise ValidationError("Cash amount given is required for cash payments.")

        if self.payment_method == 'mpesa' and not self.mpesa_reference:
            raise ValidationError("M-Pesa reference is required.")

        if self.payment_method == 'credit':
            if self.credit_amount is None:  # Only raise error if None (not 0)
                raise ValidationError("Credit amount must be specified (use 0 for no deposit).")

        if self.payment_method == 'cheque':
            if not self.cheque_number:
                raise ValidationError("Cheque number is required.")
            if not self.cheque_date:
                raise ValidationError("Cheque date is required.")
            
            # Check for duplicate cheque number for the same customer
            if self.customer and self.cheque_number:
                existing_cheque = Sale.objects.filter(
                    customer=self.customer,
                    cheque_number=self.cheque_number,
                    payment_method='cheque'
                ).exclude(id=self.id if self.id else None)
                
                if existing_cheque.exists():
                    raise ValidationError(f"Cheque number {self.cheque_number} already exists for this customer.")

            # Warning for past dates (instead of blocking)
            if self.cheque_date and self.cheque_date < timezone.now().date():
                logger.warning(
                    f"Past-dated cheque recorded: #{self.cheque_number} "
                    f"(Date: {self.cheque_date}, Amount: {self.total_amount})"
                )

    def save(self, *args, **kwargs):
        """Handle payment completion logic"""
        self.full_clean()  # Enforce validation

        # Auto-calculate change for cash payments
        if self.payment_method == 'cash' and self.cash_given:
            self.change_due = self.cash_given - self.total_amount
            self.is_complete = self.change_due >= 0

        # Mark other payment methods as complete
        elif self.payment_method in ['mpesa', 'cheque']:
            self.is_complete = True

        super().save(*args, **kwargs)

    @property
    def outstanding_credit(self):
        """Calculate remaining credit for partial payments"""
        if self.payment_method == 'credit':
            return max(self.total_amount - (self.credit_amount or 0), Decimal(0))
        return Decimal(0)


class SaleItem(models.Model):
    # Schema separation provides tenant isolation - no tenant field needed
    sale = models.ForeignKey(Sale, related_name='items', on_delete=models.CASCADE)
    product = models.ForeignKey(Product, on_delete=models.PROTECT)
    batch = models.ForeignKey(Batch, on_delete=models.PROTECT, null=True, blank=True)
    quantity = models.PositiveIntegerField()
    selling_price = models.DecimalField(max_digits=10, decimal_places=2)
    subtotal = models.DecimalField(max_digits=10, decimal_places=2, editable=False)

    def clean(self):
        """Validate stock availability"""
        if self.batch and self.quantity > self.batch.quantity:
            raise ValidationError(f"Only {self.batch.quantity} units available in batch {self.batch.batch_code}")
        elif not self.batch and self.quantity > self.product.stock_quantity:
            raise ValidationError(f"Only {self.product.stock_quantity} units available")

    def save(self, *args, **kwargs):
        """Auto-calculate prices and update stock"""
        # Set price from batch or product only if not already set
        if not self.selling_price:
            self.selling_price = self.batch.selling_price if self.batch else self.product.selling_price
        self.subtotal = self.selling_price * self.quantity
        
        super().save(*args, **kwargs)



class SalePayment(models.Model):
    """Track multiple payment methods for a single sale"""
    PAYMENT_METHOD_CHOICES = [
        ('cash', 'Cash'),
        ('mpesa', 'M-Pesa'),
        ('credit', 'Credit'),
        ('cheque', 'Cheque'),
    ]
    
    # Schema separation provides tenant isolation - no tenant field needed
    sale = models.ForeignKey(Sale, related_name='payments', on_delete=models.CASCADE)
    payment_method = models.CharField(max_length=10, choices=PAYMENT_METHOD_CHOICES)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    
    # Payment method specific fields
    mpesa_reference = models.CharField(max_length=255, null=True, blank=True)
    cheque_number = models.CharField(max_length=50, null=True, blank=True)
    cheque_date = models.DateField(null=True, blank=True)
    
    created_at = models.DateTimeField(default=now)
    
    class Meta:
        ordering = ['-created_at']
    
    def __str__(self):
        return f"Sale #{self.sale.id} - {self.get_payment_method_display()} - KSh {self.amount}"