
from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
from billing.models import Invoice
from decimal import Decimal
import uuid

User = get_user_model()

class Payment(models.Model):
    PAYMENT_METHOD_CHOICES = [
        ('mpesa', 'M-Pesa'),
        ('cash', 'Cash'),
        ('bank_transfer', 'Bank Transfer'),
        ('cheque', 'Cheque'),
        ('balance_deduction', 'Account Balance Deduction'),
    ]
    
    STATUS_CHOICES = [
        ('pending', 'Pending'),
        ('completed', 'Completed'),
        ('failed', 'Failed'),
        ('cancelled', 'Cancelled'),
    ]
    
    payment_id = models.CharField(max_length=50, unique=True)
    invoice = models.ForeignKey(Invoice, on_delete=models.CASCADE, related_name='payments', null=True, blank=True)
    customer = models.ForeignKey('customers.Customer', on_delete=models.CASCADE, related_name='payments', null=True, blank=True, help_text="For advance payments without specific invoice")
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHOD_CHOICES)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
    
    # M-Pesa specific fields
    mpesa_receipt_number = models.CharField(max_length=50, blank=True)
    mpesa_transaction_id = models.CharField(max_length=50, blank=True)
    mpesa_phone_number = models.CharField(max_length=15, blank=True)
    mpesa_callback_data = models.JSONField(null=True, blank=True)
    
    # Cash payment fields
    cash_received_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name='cash_payments_received')
    cash_receipt_number = models.CharField(max_length=50, blank=True)
    
    # Other payment details
    reference_number = models.CharField(max_length=100, blank=True)
    notes = models.TextField(blank=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)
    
    def save(self, *args, **kwargs):
        if not self.payment_id:
            # Generate unique payment ID with PAY prefix
            import uuid
            self.payment_id = f"PAY-{str(uuid.uuid4())[:8].upper()}"
        super().save(*args, **kwargs)
    
    def __str__(self):
        return f"Payment {self.payment_id} - {self.amount} - {self.get_status_display()}"

class MpesaTransaction(models.Model):
    checkout_request_id = models.CharField(max_length=100, unique=True)
    merchant_request_id = models.CharField(max_length=100)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    phone_number = models.CharField(max_length=15)
    account_reference = models.CharField(max_length=100)
    transaction_desc = models.CharField(max_length=200)
    
    # Response fields
    mpesa_receipt_number = models.CharField(max_length=50, blank=True)
    transaction_date = models.DateTimeField(null=True, blank=True)
    result_code = models.IntegerField(null=True, blank=True)
    result_desc = models.CharField(max_length=200, blank=True)
    
    payment = models.ForeignKey(Payment, on_delete=models.SET_NULL, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)
    
    def __str__(self):
        return f"M-Pesa {self.checkout_request_id} - {self.amount}"

class MpesaB2CTransaction(models.Model):
    COMMAND_CHOICES = [
        ('SalaryPayment', 'Salary Payment'),
        ('BusinessPayment', 'Business Payment'),
        ('PromotionPayment', 'Promotion Payment'),
    ]
    
    conversation_id = models.CharField(max_length=100, unique=True)
    originator_conversation_id = models.CharField(max_length=100)
    command_id = models.CharField(max_length=20, choices=COMMAND_CHOICES)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    phone_number = models.CharField(max_length=15)
    remarks = models.CharField(max_length=200)
    occasion = models.CharField(max_length=100, blank=True)
    
    # Response fields
    result_code = models.IntegerField(null=True, blank=True)
    result_desc = models.CharField(max_length=200, blank=True)
    transaction_id = models.CharField(max_length=50, blank=True)
    transaction_receipt = models.CharField(max_length=50, blank=True)
    transaction_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    working_account_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    utility_account_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    charges_paid_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    recipient_registered = models.BooleanField(default=False)
    
    created_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)
    
    def __str__(self):
        return f"B2C {self.conversation_id} - {self.amount} to {self.phone_number}"

class MpesaB2BTransaction(models.Model):
    COMMAND_CHOICES = [
        ('BusinessPayBill', 'Business Pay Bill'),
        ('BusinessBuyGoods', 'Business Buy Goods'),
        ('DisburseFundsToBusiness', 'Disburse Funds To Business'),
        ('BusinessToBusinessTransfer', 'Business To Business Transfer'),
    ]
    
    conversation_id = models.CharField(max_length=100, unique=True)
    originator_conversation_id = models.CharField(max_length=100)
    command_id = models.CharField(max_length=30, choices=COMMAND_CHOICES)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    party_a = models.CharField(max_length=20)  # Sender
    party_b = models.CharField(max_length=20)  # Receiver
    account_reference = models.CharField(max_length=100)
    remarks = models.CharField(max_length=200)
    
    # Response fields
    result_code = models.IntegerField(null=True, blank=True)
    result_desc = models.CharField(max_length=200, blank=True)
    transaction_id = models.CharField(max_length=50, blank=True)
    transaction_receipt = models.CharField(max_length=50, blank=True)
    transaction_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    working_account_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    utility_account_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    charges_paid_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)
    
    def __str__(self):
        return f"B2B {self.conversation_id} - {self.amount} from {self.party_a} to {self.party_b}"

class MpesaReversal(models.Model):
    conversation_id = models.CharField(max_length=100, unique=True)
    originator_conversation_id = models.CharField(max_length=100)
    original_transaction_id = models.CharField(max_length=50)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    receiver_party = models.CharField(max_length=20)
    remarks = models.CharField(max_length=200)
    occasion = models.CharField(max_length=100, blank=True)
    
    # Response fields
    result_code = models.IntegerField(null=True, blank=True)
    result_desc = models.CharField(max_length=200, blank=True)
    transaction_id = models.CharField(max_length=50, blank=True)
    transaction_receipt = models.CharField(max_length=50, blank=True)
    transaction_amount = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    working_account_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    utility_account_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    charges_paid_funds = models.DecimalField(max_digits=10, decimal_places=2, null=True, blank=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)
    
    def __str__(self):
        return f"Reversal {self.conversation_id} - {self.amount} for {self.original_transaction_id}"

class MpesaBalanceInquiry(models.Model):
    conversation_id = models.CharField(max_length=100, unique=True)
    originator_conversation_id = models.CharField(max_length=100)
    
    # Response fields
    result_code = models.IntegerField(null=True, blank=True)
    result_desc = models.CharField(max_length=200, blank=True)
    working_account_funds = models.DecimalField(max_digits=15, decimal_places=2, null=True, blank=True)
    utility_account_funds = models.DecimalField(max_digits=15, decimal_places=2, null=True, blank=True)
    charges_paid_funds = models.DecimalField(max_digits=15, decimal_places=2, null=True, blank=True)
    
    created_at = models.DateTimeField(auto_now_add=True)
    completed_at = models.DateTimeField(null=True, blank=True)
    
    def __str__(self):
        return f"Balance Inquiry {self.conversation_id} - {self.created_at}"

class UnreconciledPayment(models.Model):
    REASON_CHOICES = [
        ('invalid_account', 'Invalid Account Number'),
        ('account_not_found', 'Account Number Not Found'),
        ('duplicate_transaction', 'Duplicate Transaction'),
        ('invalid_amount', 'Invalid Amount'),
        ('system_error', 'System Error'),
    ]
    
    STATUS_CHOICES = [
        ('pending', 'Pending Review'),
        ('resolved', 'Resolved'),
        ('refunded', 'Refunded'),
        ('ignored', 'Ignored'),
    ]
    
    # Transaction details
    transaction_id = models.CharField(max_length=50, unique=True)
    phone_number = models.CharField(max_length=15)
    amount = models.DecimalField(max_digits=10, decimal_places=2)
    account_reference = models.CharField(max_length=100, help_text="The account number customer tried to pay to")
    transaction_time = models.DateTimeField()
    
    # Customer details from transaction
    first_name = models.CharField(max_length=50, blank=True)
    middle_name = models.CharField(max_length=50, blank=True)
    last_name = models.CharField(max_length=50, blank=True)
    
    # Reconciliation details
    reason = models.CharField(max_length=25, choices=REASON_CHOICES, default='invalid_account')
    status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='pending')
    notes = models.TextField(blank=True, help_text="Admin notes about this unreconciled payment")
    
    # Resolution details
    resolved_customer = models.ForeignKey('customers.Customer', on_delete=models.SET_NULL, null=True, blank=True, help_text="Customer this payment was eventually assigned to")
    resolved_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
    resolved_at = models.DateTimeField(null=True, blank=True)
    
    # Raw callback data
    callback_data = models.JSONField(null=True, blank=True)
    
    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"Unreconciled: {self.transaction_id} - KES {self.amount} ({self.account_reference})"
    
    @property
    def customer_name(self):
        return f"{self.first_name} {self.middle_name} {self.last_name}".strip()
    
    def resolve_to_customer(self, customer, resolved_by_user, notes=""):
        """Resolve this unreconciled payment to a specific customer"""
        from decimal import Decimal
        
        # Ensure transaction_time is timezone-aware
        transaction_time = self.transaction_time
        if transaction_time and timezone.is_naive(transaction_time):
            transaction_time = timezone.make_aware(transaction_time)
        
        # Create payment record for the customer
        payment = Payment.objects.create(
            customer=customer,
            amount=self.amount,
            payment_method='mpesa',
            status='completed',
            mpesa_receipt_number=self.transaction_id,
            mpesa_phone_number=self.phone_number,
            reference_number=f"RESOLVED-{self.transaction_id}",
            notes=f"Resolved unreconciled payment. Original account ref: {self.account_reference}. {notes}".strip(),
            completed_at=transaction_time or timezone.now()
        )
        
        # Update customer balance
        from customers.services import CustomerBalanceService
        CustomerBalanceService.add_balance(
            customer=customer,
            amount=self.amount,
            description=f"Resolved M-Pesa payment - {self.transaction_id}",
            reference_id=payment.payment_id,
            processed_by=resolved_by_user
        )
        
        # Mark as resolved
        self.status = 'resolved'
        self.resolved_customer = customer
        self.resolved_by = resolved_by_user
        self.resolved_at = timezone.now()
        if notes:
            self.notes = f"{self.notes}\n{notes}".strip()
        self.save()
        
        return payment
