# sales/models.py
import random
import string
from django.db import models
from inventory.models import Product
from core.models import SystemSettings
from decimal import Decimal
from django.db.models import Sum, Count, Q


# ─────────────────────────────────────────────────────────────
# HELPER: generate mixed-case alphanumeric order number suffix
# ─────────────────────────────────────────────────────────────
def _random_suffix(k=5):
    """Return k random uppercase alphanumeric characters."""
    return ''.join(random.choices(string.ascii_uppercase + string.digits, k=k))


class POSOrder(models.Model):
    # Payment methods – 'credit' removed; use payment_status instead
    PAYMENT_METHODS = [
        ('pos', 'POS/ATM Card'),
        ('transfer', 'Bank Transfer'),
        ('cash', 'Cash'),
        ('mobile_money', 'Mobile Money'),
    ]

    ORDER_STATUS = [
        ('pending', 'Pending'),
        ('completed', 'Completed'),
        ('cancelled', 'Cancelled'),
    ]

    PAYMENT_STATUS_CHOICES = [
        ('full', 'Paid in Full'),
        ('partial', 'Partial Payment'),
        ('credit', 'Credit / Customer Owing'),
    ]

    order_number = models.CharField(max_length=60, unique=True)

    # Deduplication key for offline sync
    client_id = models.CharField(
        max_length=64, blank=True, db_index=True,
        help_text="UUID generated by the client to prevent duplicate offline orders."
    )

    # Money fields
    total_amount   = models.DecimalField(max_digits=10, decimal_places=2)
    discount_amount = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    tax_amount     = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    final_amount   = models.DecimalField(max_digits=10, decimal_places=2)

    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHODS, default='cash')
    status = models.CharField(max_length=15, choices=ORDER_STATUS, default='pending')

    # Credit tracking
    payment_status = models.CharField(
        max_length=10,
        choices=PAYMENT_STATUS_CHOICES,
        default='full',
        help_text="Whether the order is fully paid or has an outstanding balance."
    )
    amount_paid = models.DecimalField(max_digits=10, decimal_places=2, default=0)
    balance_amount = models.DecimalField(
        max_digits=10, decimal_places=2, default=0,
        help_text="Outstanding balance = final_amount - amount_paid."
    )

    # Customer info — name/phone kept for walk-in / legacy orders
    customer_name  = models.CharField(max_length=100, blank=True)
    customer_phone = models.CharField(max_length=15, blank=True)

    # FK to registered Customer (optional; set when customer selected at POS)
    customer = models.ForeignKey(
        'sales.Customer',
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name='orders',
    )

    # Branch
    branch = models.ForeignKey(
        'core.Branch',
        on_delete=models.SET_NULL,
        null=True, blank=True,
        related_name='pos_orders'
    )

    # Staff
    cashier    = models.CharField(max_length=100)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def clear_credit(self, amount=None):
        """
        Clears customer credit. Accepts partial or full amount.
        """
        if amount is None:
            amount = self.balance_amount
        if not isinstance(amount, Decimal):
            amount = Decimal(str(amount))
        if amount <= 0:
            return False

        self.amount_paid   = (self.amount_paid or Decimal("0")) + amount
        self.balance_amount = self.final_amount - self.amount_paid

        if self.balance_amount <= 0:
            self.balance_amount = Decimal("0")
            self.payment_status = "full"
        elif self.amount_paid > 0:
            self.payment_status = "partial"
        else:
            self.payment_status = "credit"

        self.save()
        return True

    @property
    def is_fully_paid(self):
        return self.balance_amount <= 0

    def __str__(self):
        return self.order_number


class POSOrderItem(models.Model):
    order    = models.ForeignKey(POSOrder, on_delete=models.CASCADE, related_name='items')
    # Product protected from deletion; name snapshot preserved
    product  = models.ForeignKey(
        Product,
        on_delete=models.SET_NULL,
        null=True, blank=True,
    )
    product_name = models.CharField(
        max_length=200, blank=True,
        help_text="Snapshot of product name at time of sale."
    )
    quantity   = models.PositiveIntegerField()
    unit_price = models.DecimalField(max_digits=10, decimal_places=2)
    total_price = models.DecimalField(max_digits=10, decimal_places=2)

    class Meta:
        verbose_name = 'POS Order Item'
        verbose_name_plural = 'POS Order Items'

    def save(self, *args, **kwargs):
        # Auto-snapshot product name
        if self.product and not self.product_name:
            self.product_name = self.product.name
        super().save(*args, **kwargs)

    def __str__(self):
        name = self.product_name or (self.product.name if self.product else 'Unknown')
        return f"{self.quantity}x {name}"


class POSReceiptSettings(models.Model):
    order = models.OneToOneField(POSOrder, on_delete=models.CASCADE, related_name='receipt_settings')
    show_product_details = models.BooleanField(default=True)
    show_customer_info   = models.BooleanField(default=True)
    show_payment_info    = models.BooleanField(default=True)
    custom_message       = models.TextField(blank=True)
    created_at           = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Receipt settings for {self.order.order_number}"


class PaymentTransaction(models.Model):
    PAYMENT_METHODS = [
        ('pos', 'POS/ATM Card'),
        ('transfer', 'Bank Transfer'),
        ('cash', 'Cash'),
        ('mobile_money', 'Mobile Money'),
        ('paystack', 'Paystack'),
        ('flutterwave', 'Flutterwave'),
    ]

    TRANSACTION_STATUS = [
        ('pending', 'Pending'),
        ('completed', 'Completed'),
        ('failed', 'Failed'),
        ('cancelled', 'Cancelled'),
    ]

    order          = models.ForeignKey(POSOrder, on_delete=models.CASCADE, related_name='payments')
    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHODS)
    amount         = models.DecimalField(max_digits=10, decimal_places=2)
    reference_number = models.CharField(max_length=100, blank=True)
    transaction_id   = models.CharField(max_length=100, blank=True)
    status           = models.CharField(max_length=15, choices=TRANSACTION_STATUS, default='pending')
    gateway_response = models.JSONField(default=dict, blank=True)
    created_at       = models.DateTimeField(auto_now_add=True)
    updated_at       = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Payment Transaction'
        verbose_name_plural = 'Payment Transactions'
        ordering = ['-created_at']

    def __str__(self):
        return f"{self.payment_method} - {self.amount} - {self.status}"


# ─── DailySalesSummary (was: SaleSummary merged into this) ────────────────────
class DailySalesSummary(models.Model):
    """Single pre-computed daily summary. SaleSummary was removed (duplicate)."""
    date              = models.DateField(unique=True)
    total_revenue     = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    total_transactions = models.PositiveIntegerField(default=0)

    cash_revenue      = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    cash_transactions = models.PositiveIntegerField(default=0)

    transfer_revenue      = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    transfer_transactions = models.PositiveIntegerField(default=0)

    pos_revenue      = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    pos_transactions = models.PositiveIntegerField(default=0)

    mobile_money_revenue      = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    mobile_money_transactions = models.PositiveIntegerField(default=0)

    top_selling_items  = models.JSONField(default=list, blank=True)
    total_profit       = models.DecimalField(max_digits=12, decimal_places=2, default=0)
    credit_outstanding = models.DecimalField(max_digits=12, decimal_places=2, default=0)

    # Cached P&L columns (set by generate_summary_from_queryset)
    total_cost    = models.DecimalField(max_digits=12, decimal_places=2, default=0)

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Daily Sales Summary'
        verbose_name_plural = 'Daily Sales Summaries'
        ordering = ['-date']

    def __str__(self):
        return f"Sales Summary for {self.date}"

    @classmethod
    def generate_summary_from_queryset(cls, date, orders):
        """Generate summary ONLY from branch-limited queryset."""
        summary_data = {
            'date': date,
            'total_revenue': orders.aggregate(total=Sum('final_amount'))['total'] or Decimal("0"),
            'total_transactions': orders.count(),
        }

        for method in ['cash', 'transfer', 'pos', 'mobile_money']:
            m_orders = orders.filter(payment_method=method)
            summary_data[f'{method}_revenue']      = m_orders.aggregate(total=Sum('final_amount'))['total'] or 0
            summary_data[f'{method}_transactions'] = m_orders.count()

        total_profit = Decimal("0")
        total_cost   = Decimal("0")
        items = POSOrderItem.objects.filter(order__in=orders).select_related("product")
        for item in items:
            selling = item.unit_price or 0
            cost    = (item.product.cost_price if item.product else None) or 0
            profit  = (Decimal(str(selling)) - Decimal(str(cost))) * item.quantity
            total_profit += profit
            total_cost   += Decimal(str(cost)) * item.quantity

        summary_data['total_profit'] = total_profit
        summary_data['total_cost']   = total_cost
        summary_data['credit_outstanding'] = (
            orders.filter(balance_amount__gt=0).aggregate(total=Sum('balance_amount'))['total'] or 0
        )

        summary, _ = cls.objects.update_or_create(date=date, defaults=summary_data)
        return summary


class UnusualTransaction(models.Model):
    order       = models.ForeignKey(POSOrder, on_delete=models.CASCADE)
    reason      = models.CharField(max_length=200)
    flagged_by  = models.CharField(max_length=100)
    flagged_at  = models.DateTimeField(auto_now_add=True)
    resolved    = models.BooleanField(default=False)
    resolved_by = models.CharField(max_length=100, blank=True)
    resolved_at = models.DateTimeField(blank=True, null=True)

    class Meta:
        verbose_name = 'Unusual Transaction'
        verbose_name_plural = 'Unusual Transactions'
        ordering = ['-flagged_at']

    def __str__(self):
        return f"Unusual: {self.order.order_number} - {self.reason}"


# ─────────────────────────────────────────────────────────────
# CASH RECONCILIATION (new — end-of-day)
# ─────────────────────────────────────────────────────────────
class CashReconciliation(models.Model):
    date     = models.DateField(unique=True)
    expected = models.DecimalField(max_digits=12, decimal_places=2, default=0,
                                   help_text="Sum of cash orders for this day.")
    actual   = models.DecimalField(max_digits=12, decimal_places=2, default=0,
                                   help_text="Physical cash count entered by cashier.")
    variance = models.DecimalField(max_digits=12, decimal_places=2, default=0,
                                   help_text="actual - expected (positive = surplus, negative = shortage).")
    cashier  = models.CharField(max_length=100, blank=True)
    notes    = models.TextField(blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        verbose_name = 'Cash Reconciliation'
        verbose_name_plural = 'Cash Reconciliations'
        ordering = ['-date']

    def save(self, *args, **kwargs):
        self.variance = self.actual - self.expected
        super().save(*args, **kwargs)

    def __str__(self):
        return f"Reconciliation {self.date} — variance {self.variance}"


# ─────────────────────────────────────────────────────────────
# CUSTOMER MODEL
# ─────────────────────────────────────────────────────────────
class Customer(models.Model):
    """Persistent customer record."""
    name       = models.CharField(max_length=150)
    phone      = models.CharField(max_length=20, blank=True)
    email      = models.EmailField(blank=True)
    address    = models.TextField(blank=True)
    notes      = models.TextField(blank=True)
    created_by = models.CharField(max_length=100, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        verbose_name = 'Customer'
        verbose_name_plural = 'Customers'
        ordering = ['name']

    def __str__(self):
        return f"{self.name} ({self.phone})" if self.phone else self.name

    @property
    def total_orders(self):
        return self.orders.count()

    @property
    def total_spent(self):
        result = self.orders.filter(status='completed').aggregate(total=Sum('final_amount'))
        return result['total'] or 0

    @property
    def outstanding_balance(self):
        result = self.orders.filter(balance_amount__gt=0).aggregate(total=Sum('balance_amount'))
        return result['total'] or 0