from django.db import models
from django.contrib.auth import get_user_model
from django.utils import timezone
import uuid
from django.conf import settings

User = get_user_model()


class OfferLetter(models.Model):
    """
    Loan offer letter generation and tracking
    """
    STATUS_CHOICES = [
        ('draft', 'Draft'),
        ('sent', 'Sent'),
        ('signed', 'Signed'),
        ('expired', 'Expired'),
        ('cancelled', 'Cancelled'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    application = models.OneToOneField('loans.LoanApplication', on_delete=models.CASCADE)
    borrower = models.ForeignKey(User, on_delete=models.CASCADE)
    
    # Offer details
    offer_number = models.CharField(max_length=20, unique=True)
    loan_amount = models.DecimalField(max_digits=12, decimal_places=2)
    interest_rate = models.DecimalField(max_digits=5, decimal_places=2)
    duration_days = models.PositiveIntegerField()
    processing_fee = models.DecimalField(max_digits=12, decimal_places=2)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2)
    
    # Terms and conditions
    terms_conditions = models.TextField()
    special_conditions = models.TextField(blank=True, null=True)
    
    # Status
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='draft')
    valid_until = models.DateTimeField()
    
    # Document
    pdf_file = models.FileField(upload_to='offer_letters/', blank=True, null=True)
    
    # Digital signature
    borrower_signature = models.TextField(blank=True, null=True)
    signed_at = models.DateTimeField(blank=True, null=True)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    sent_at = models.DateTimeField(blank=True, null=True)
    
    class Meta:
        db_table = 'offer_letters'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"Offer Letter {self.offer_number} - {self.borrower.get_full_name()}"
    
    def save(self, *args, **kwargs):
        if not self.offer_number:
            # Generate offer number
            last_offer = OfferLetter.objects.order_by('-id').first()
            if last_offer:
                last_num = int(last_offer.offer_number.split('-')[1])
                self.offer_number = f"OFFER-{last_num + 1:06d}"
            else:
                self.offer_number = "OFFER-000001"
        
        if not self.valid_until:
            self.valid_until = timezone.now() + timezone.timedelta(days=7)
        
        super().save(*args, **kwargs)
    
    def is_expired(self):
        return timezone.now() > self.valid_until
    
    def mark_as_sent(self):
        self.status = 'sent'
        self.sent_at = timezone.now()
        self.save()
    
    def sign_offer(self, signature_data):
        self.status = 'signed'
        self.borrower_signature = signature_data
        self.signed_at = timezone.now()
        self.save()


class Receipt(models.Model):
    """
    Payment receipt generation
    """
    PAYMENT_METHODS = [
        ('mpesa', 'M-Pesa'),
        ('bank', 'Bank Transfer'),
        ('cash', 'Cash'),
        ('cheque', 'Cheque'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    repayment = models.OneToOneField('loans.Repayment', on_delete=models.CASCADE)
    loan = models.ForeignKey('loans.Loan', on_delete=models.CASCADE)
    borrower = models.ForeignKey(User, on_delete=models.CASCADE)
    
    # Receipt details
    receipt_number = models.CharField(max_length=20, unique=True)
    amount_paid = models.DecimalField(max_digits=12, decimal_places=2)
    payment_method = models.CharField(max_length=20, choices=PAYMENT_METHODS)
    payment_date = models.DateTimeField()
    
    # Balance information
    previous_balance = models.DecimalField(max_digits=12, decimal_places=2)
    new_balance = models.DecimalField(max_digits=12, decimal_places=2)
    
    # Document
    pdf_file = models.FileField(upload_to='receipts/', blank=True, null=True)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        db_table = 'receipts'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"Receipt {self.receipt_number} - {self.borrower.get_full_name()}"
    
    def save(self, *args, **kwargs):
        if not self.receipt_number:
            # Generate receipt number
            last_receipt = Receipt.objects.order_by('-id').first()
            if last_receipt:
                last_num = int(last_receipt.receipt_number.split('-')[1])
                self.receipt_number = f"RCP-{last_num + 1:06d}"
            else:
                self.receipt_number = "RCP-000001"
        super().save(*args, **kwargs)


class LoanStatement(models.Model):
    """
    Loan statement generation for borrowers
    """
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    loan = models.ForeignKey('loans.Loan', on_delete=models.CASCADE)
    borrower = models.ForeignKey(User, on_delete=models.CASCADE)
    
    # Statement details
    statement_number = models.CharField(max_length=20, unique=True)
    statement_date = models.DateTimeField(auto_now_add=True)
    period_from = models.DateTimeField()
    period_to = models.DateTimeField()
    
    # Loan summary
    principal_amount = models.DecimalField(max_digits=12, decimal_places=2)
    interest_amount = models.DecimalField(max_digits=12, decimal_places=2)
    total_amount = models.DecimalField(max_digits=12, decimal_places=2)
    amount_paid = models.DecimalField(max_digits=12, decimal_places=2)
    outstanding_balance = models.DecimalField(max_digits=12, decimal_places=2)
    
    # Document
    pdf_file = models.FileField(upload_to='loan_statements/', blank=True, null=True)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    
    class Meta:
        db_table = 'loan_statements'
        ordering = ['-created_at']
    
    def __str__(self):
        return f"Statement {self.statement_number} - {self.borrower.get_full_name()}"
    
    def save(self, *args, **kwargs):
        if not self.statement_number:
            # Generate statement number
            last_statement = LoanStatement.objects.order_by('-id').first()
            if last_statement:
                last_num = int(last_statement.statement_number.split('-')[1])
                self.statement_number = f"STMT-{last_num + 1:06d}"
            else:
                self.statement_number = "STMT-000001"
        super().save(*args, **kwargs)


class DocumentTemplate(models.Model):
    """
    Document templates for various loan documents
    """
    TEMPLATE_TYPES = [
        ('offer_letter', 'Offer Letter'),
        ('receipt', 'Receipt'),
        ('statement', 'Loan Statement'),
        ('agreement', 'Loan Agreement'),
        ('welcome_letter', 'Welcome Letter'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=200)
    template_type = models.CharField(max_length=30, choices=TEMPLATE_TYPES)
    description = models.TextField(blank=True, null=True)
    
    # Template content
    html_template = models.TextField()
    css_styles = models.TextField(blank=True, null=True)
    
    # Configuration
    is_active = models.BooleanField(default=True)
    is_default = models.BooleanField(default=False)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'document_templates'
        ordering = ['template_type', 'name']
    
    def __str__(self):
        return f"{self.name} ({self.get_template_type_display()})"


class EmailTemplate(models.Model):
    """
    Email templates for notifications
    """
    TEMPLATE_TYPES = [
        ('welcome', 'Welcome Email'),
        ('loan_approved', 'Loan Approved'),
        ('loan_rejected', 'Loan Rejected'),
        ('payment_reminder', 'Payment Reminder'),
        ('overdue_alert', 'Overdue Alert'),
        ('offer_letter', 'Offer Letter'),
        ('password_reset', 'Password Reset'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=200)
    template_type = models.CharField(max_length=30, choices=TEMPLATE_TYPES)
    subject = models.CharField(max_length=200)
    
    # Template content
    html_content = models.TextField()
    text_content = models.TextField(blank=True, null=True)
    
    # Configuration
    is_active = models.BooleanField(default=True)
    is_default = models.BooleanField(default=False)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'email_templates'
        ordering = ['template_type', 'name']
    
    def __str__(self):
        return f"{self.name} ({self.get_template_type_display()})"


class SMSTemplate(models.Model):
    """
    SMS templates for notifications
    """
    TEMPLATE_TYPES = [
        ('welcome', 'Welcome SMS'),
        ('loan_approved', 'Loan Approved'),
        ('loan_rejected', 'Loan Rejected'),
        ('payment_reminder', 'Payment Reminder'),
        ('overdue_alert', 'Overdue Alert'),
        ('otp', 'OTP Verification'),
    ]
    
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=200)
    template_type = models.CharField(max_length=30, choices=TEMPLATE_TYPES)
    
    # Template content
    message_template = models.TextField()
    
    # Configuration
    is_active = models.BooleanField(default=True)
    is_default = models.BooleanField(default=False)
    
    # Timestamps
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    
    class Meta:
        db_table = 'sms_templates'
        ordering = ['template_type', 'name']
    
    def __str__(self):
        return f"{self.name} ({self.get_template_type_display()})"


class AuditLog(models.Model):
    """Model for tracking user actions and system changes"""
    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)
    action = models.CharField(max_length=50, choices=[
        ('create', 'Create'),
        ('update', 'Update'),
        ('delete', 'Delete'),
        ('login', 'Login'),
        ('logout', 'Logout'),
        ('payment', 'Payment'),
    ])
    model_name = models.CharField(max_length=100)
    object_id = models.CharField(max_length=50)
    description = models.TextField()
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.CharField(max_length=255, null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['-created_at']
        verbose_name = 'Audit Log'
        verbose_name_plural = 'Audit Logs'

    def __str__(self):
        return f"{self.action} by {self.user} on {self.created_at}"

class DocumentTag(models.Model):
    """Tags for categorizing documents"""
    name = models.CharField(max_length=50, unique=True)
    created_at = models.DateTimeField(auto_now_add=True)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['name']

class Document(models.Model):
    DOCUMENT_TYPES = [
        ('loan_agreement', 'Loan Agreement'),
        ('id_document', 'ID Document'),
        ('selfie', 'Selfie Photo'),
        ('utility_bill', 'Utility Bill'),
        ('bank_statement', 'Bank Statement'),
        ('business_license', 'Business License'),
        ('tax_return', 'Tax Return'),
        ('payslip', 'Payslip'),
        ('contract', 'Contract'),
        ('logbook', 'Logbook'),
        ('title_deed', 'Title Deed'),
        ('signature', 'Signature'),
        ('other', 'Other')
    ]

    name = models.CharField(max_length=255, default='Untitled Document')
    file = models.FileField(upload_to='documents/')
    document_type = models.CharField(max_length=50, choices=DOCUMENT_TYPES, default='other')
    uploaded_by = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    description = models.TextField(blank=True, null=True)
    
    # New fields
    tags = models.ManyToManyField(DocumentTag, blank=True)
    shared_with = models.ManyToManyField(
        settings.AUTH_USER_MODEL,
        through='DocumentShare',
        related_name='shared_documents',
        through_fields=('document', 'shared_with')
    )
    thumbnail = models.ImageField(upload_to='documents/thumbnails/', blank=True, null=True)
    file_size = models.PositiveIntegerField(default=0)  # in bytes
    mime_type = models.CharField(max_length=100, blank=True)
    is_public = models.BooleanField(default=False)

    def __str__(self):
        return self.name

    class Meta:
        ordering = ['-created_at']

    def save(self, *args, **kwargs):
        # Update file size if file is present
        if self.file:
            self.file_size = self.file.size
        super().save(*args, **kwargs)

class DocumentShare(models.Model):
    """Track document sharing between users"""
    document = models.ForeignKey(Document, on_delete=models.CASCADE)
    shared_with = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    shared_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        related_name='documents_shared'
    )
    shared_at = models.DateTimeField(auto_now_add=True)
    message = models.TextField(blank=True, null=True)
    is_read = models.BooleanField(default=False)

    class Meta:
        unique_together = ['document', 'shared_with']
        ordering = ['-shared_at']

    def __str__(self):
        return f"{self.document.name} shared with {self.shared_with.get_full_name()}"

    def save(self, *args, **kwargs):
        # Create notification for shared user
        if not self.pk:  # Only on creation
            Notification.objects.create(
                title='Document Shared',
                message=f'{self.shared_by.get_full_name()} shared a document with you: {self.document.name}',
                priority='medium',
                user=self.shared_with,
                action_url=f'/utils/documents/view/{self.document.id}/'
            )
        super().save(*args, **kwargs)

class Notification(models.Model):
    NOTIFICATION_TYPES = [
        ('loan_approved', 'Loan Approved'),
        ('loan_rejected', 'Loan Rejected'),
        ('payment_due', 'Payment Due'),
        ('payment_received', 'Payment Received'),
        ('document_uploaded', 'Document Uploaded'),
        ('document_rejected', 'Document Rejected'),
        ('loan_overdue', 'Loan Overdue'),
        ('credit_score_update', 'Credit Score Update'),
        ('system_maintenance', 'System Maintenance'),
        ('security_alert', 'Security Alert'),
        ('profile_update', 'Profile Update'),
        ('new_feature', 'New Feature'),
        ('application_submitted', 'Application Submitted'),
        ('application_reviewed', 'Application Reviewed'),
        ('loan_disbursed', 'Loan Disbursed'),
        ('repayment_reminder', 'Repayment Reminder'),
        ('late_payment', 'Late Payment'),
        ('loan_completed', 'Loan Completed'),
        ('rollover_request', 'Rollover Request'),
        ('rollover_approved', 'Rollover Approved'),
        ('rollover_rejected', 'Rollover Rejected'),
        ('document_expired', 'Document Expired'),
        ('kyc_required', 'KYC Required'),
        ('kyc_completed', 'KYC Completed'),
        ('kyc_rejected', 'KYC Rejected'),
        ('system_update', 'System Update'),
        ('maintenance_scheduled', 'Maintenance Scheduled'),
        ('login_alert', 'Login Alert'),
        ('password_changed', 'Password Changed'),
        ('account_locked', 'Account Locked'),
        ('account_unlocked', 'Account Unlocked'),
        ('loan_extension', 'Loan Extension'),
        ('penalty_applied', 'Penalty Applied'),
        ('refund_processed', 'Refund Processed'),
        ('statement_ready', 'Statement Ready'),
        ('receipt_generated', 'Receipt Generated'),
        ('offer_letter_sent', 'Offer Letter Sent'),
        ('offer_letter_signed', 'Offer Letter Signed'),
        ('collateral_required', 'Collateral Required'),
        ('collateral_verified', 'Collateral Verified'),
        ('collateral_rejected', 'Collateral Rejected'),
        # Portfolio Performance Alerts
        ('portfolio_alert', 'Portfolio Alert'),
        ('portfolio_health_critical', 'Critical Portfolio Health'),
        ('portfolio_health_warning', 'Portfolio Health Warning'),
        ('high_default_rate', 'High Default Rate'),
        ('low_collection_rate', 'Low Collection Rate'),
        ('high_par', 'High Portfolio at Risk'),
        ('negative_growth', 'Negative Portfolio Growth'),
        ('portfolio_milestone', 'Portfolio Milestone'),
        ('performance_summary', 'Performance Summary'),
    ]
    
    PRIORITY_LEVELS = [
        ('low', 'Low'),
        ('medium', 'Medium'),
        ('high', 'High'),
        ('urgent', 'Urgent'),
    ]

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name='system_notifications', null=True, blank=True)
    notification_type = models.CharField(max_length=50, choices=NOTIFICATION_TYPES, default='system_maintenance')
    title = models.CharField(max_length=200)
    message = models.TextField()
    priority = models.CharField(max_length=20, choices=PRIORITY_LEVELS, default='medium')
    created_at = models.DateTimeField(auto_now_add=True)
    read_at = models.DateTimeField(null=True, blank=True)
    action_url = models.CharField(max_length=200, blank=True, null=True)
    expires_at = models.DateTimeField(null=True, blank=True)
    icon = models.CharField(max_length=50, default='fa-bell')
    loan_app = models.ForeignKey('loans.LoanApplication', on_delete=models.CASCADE, null=True, blank=True, related_name='notifications_as_utils')
    related_loan = models.ForeignKey('loans.Loan', on_delete=models.CASCADE, null=True, blank=True, related_name='utils_notifications')
    
    # Portfolio-specific fields
    action_required = models.BooleanField(default=False, help_text="Whether this notification requires immediate action")
    # portfolio_snapshot = models.ForeignKey('users.PortfolioSnapshot', on_delete=models.CASCADE, null=True, blank=True, related_name='notifications')
    alert_data = models.JSONField(default=dict, blank=True, help_text="Additional alert data in JSON format")

    class Meta:
        ordering = ['-created_at']
        indexes = [
            models.Index(fields=['user', '-created_at']),
            models.Index(fields=['notification_type']),
            models.Index(fields=['read_at']),  # This is the correct field to index
        ]

    def __str__(self):
        return f"{self.notification_type} - {self.title}"

    def mark_as_read(self):
        self.read_at = timezone.now()
        self.save()

    def is_read(self):
        return self.read_at is not None

    def is_expired(self):
        if self.expires_at:
            return timezone.now() > self.expires_at
        return False

    @property
    def age(self):
        """Return the age as a datetime object for timesince filter"""
        return self.created_at

    @property
    def age_display(self):
        """Return a human-readable age string"""
        from django.utils import timezone
        from django.utils.timesince import timesince
        return timesince(self.created_at, timezone.now())

    @classmethod
    def create_notification(cls, user, notification_type, title, message, priority='medium', 
                          action_url=None, expires_in_days=None, icon=None):
        """
        Helper method to create notifications with standard formatting
        """
        expires_at = None
        if expires_in_days:
            expires_at = timezone.now() + timezone.timedelta(days=expires_in_days)
            
        if icon is None:
            icon = cls.get_default_icon(notification_type)
            
        return cls.objects.create(
            user=user,
            notification_type=notification_type,
            title=title,
            message=message,
            priority=priority,
            action_url=action_url,
            expires_at=expires_at,
            icon=icon
        )

    @staticmethod
    def get_default_icon(notification_type):
        """
        Returns the default icon class for a notification type
        """
        icon_map = {
            'loan_approved': 'fa-check-circle',
            'loan_rejected': 'fa-times-circle',
            'payment_due': 'fa-calendar',
            'payment_received': 'fa-money-bill',
            'document_uploaded': 'fa-file-upload',
            'document_rejected': 'fa-file-excel',
            'loan_overdue': 'fa-exclamation-triangle',
            'credit_score_update': 'fa-chart-line',
            'system_maintenance': 'fa-wrench',
            'security_alert': 'fa-shield-alt',
            'profile_update': 'fa-user',
            'new_feature': 'fa-star',
            'application_submitted': 'fa-file-alt',
            'application_reviewed': 'fa-eye',
            'loan_disbursed': 'fa-money-bill-wave',
            'repayment_reminder': 'fa-clock',
            'late_payment': 'fa-exclamation-circle',
            'loan_completed': 'fa-check-double',
            'rollover_request': 'fa-sync',
            'rollover_approved': 'fa-check-circle',
            'rollover_rejected': 'fa-times-circle',
            'document_expired': 'fa-calendar-times',
            'kyc_required': 'fa-id-card',
            'kyc_completed': 'fa-check-circle',
            'kyc_rejected': 'fa-times-circle',
            'system_update': 'fa-download',
            'maintenance_scheduled': 'fa-tools',
            'login_alert': 'fa-sign-in-alt',
            'password_changed': 'fa-key',
            'account_locked': 'fa-lock',
            'account_unlocked': 'fa-unlock',
            'loan_extension': 'fa-calendar-plus',
            'penalty_applied': 'fa-exclamation-triangle',
            'refund_processed': 'fa-undo',
            'statement_ready': 'fa-file-invoice',
            'receipt_generated': 'fa-receipt',
            'offer_letter_sent': 'fa-envelope',
            'offer_letter_signed': 'fa-signature',
            'collateral_required': 'fa-shield-alt',
            'collateral_verified': 'fa-check-circle',
            'collateral_rejected': 'fa-times-circle',
        }
        return icon_map.get(notification_type, 'fa-bell')

class SystemSetting(models.Model):
    CATEGORIES = [
        ('system', 'System'),
        ('loan', 'Loan'),
        ('notification', 'Notification'),
        ('document', 'Document')
    ]

    key = models.CharField(max_length=50, unique=True)
    value = models.TextField(default='')
    category = models.CharField(max_length=20, choices=CATEGORIES, default='system')
    description = models.TextField(blank=True, null=True)
    is_public = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    def __str__(self):
        return f"{self.key} ({self.category})"

    class Meta:
        ordering = ['category', 'key']

    @classmethod
    def get_setting(cls, key, default=None):
        try:
            return cls.objects.get(key=key).value
        except cls.DoesNotExist:
            return default

    @classmethod
    def get_int(cls, key, default=0):
        try:
            return int(cls.get_setting(key, default))
        except (ValueError, TypeError):
            return default

    @classmethod
    def get_float(cls, key, default=0.0):
        try:
            return float(cls.get_setting(key, default))
        except (ValueError, TypeError):
            return default

    @classmethod
    def get_bool(cls, key, default=False):
        value = cls.get_setting(key, default)
        if isinstance(value, bool):
            return value
        return str(value).lower() in ('true', '1', 'yes', 'on')

    @classmethod
    def get_loan_settings(cls):
        """Get all loan-related settings"""
        return {
            'min_amount': cls.get_float('min_loan_amount', 1000),
            'max_amount': cls.get_float('max_loan_amount', 500000),
            'default_duration': cls.get_int('default_loan_duration', 30),
            'default_interest_rate': cls.get_float('default_interest_rate', 15),
            'late_payment_penalty': cls.get_float('late_payment_penalty', 5),
            'processing_fee': cls.get_float('processing_fee', 1),
            'auto_approve_limit': cls.get_float('auto_approve_limit', 50000),
            'min_credit_score': cls.get_int('min_credit_score', 60)
        }
