from django.db import models
from django.conf import settings
from django.db.models import Sum
from django.utils import timezone
from properties.models import Unit
from payments.services.notifications import notify_user

User = settings.AUTH_USER_MODEL

class Invoice(models.Model):

    STATUS_CHOICES = (
        ('pending', 'Pending'),
        ('paid', 'Paid'),
        ('partial', 'Partial'),
        ('overdue', 'Overdue'),
    )

    tenant = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='invoices'
    )

    unit = models.ForeignKey(
        Unit,
        on_delete=models.CASCADE,
        related_name='invoices'
    )

    amount = models.DecimalField(max_digits=10, decimal_places=2)
    due_date = models.DateField()

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='pending'
    )

    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"Invoice {self.id} - {self.tenant}"

    # ================= PAYMENTS =================
    @property
    def total_paid(self):
        return self.payments.aggregate(
            total=Sum('amount')
        )['total'] or 0

    @property
    def balance(self):
        return self.amount - self.total_paid

    # ================= STATUS ENGINE =================
    def update_status(self):
        today = timezone.now().date()

        if self.balance <= 0:
            new_status = "paid"

        elif self.total_paid > 0:
            new_status = "partial"

        elif today > self.due_date:
            new_status = "overdue"

        else:
            new_status = "pending"

        if self.status != new_status:
            self.status = new_status
            self.save(update_fields=["status"])


class Payment(models.Model):

    STATUS_CHOICES = (
        ('completed', 'Completed'),
        ('pending', 'Pending'),
        ('failed', 'Failed'),
    )

    tenant = models.ForeignKey(
        User,
        on_delete=models.CASCADE,
        related_name='payments'
    )

    invoice = models.ForeignKey(
        Invoice,
        on_delete=models.CASCADE,
        related_name='payments'
    )

    unit = models.ForeignKey(
        Unit,
        on_delete=models.CASCADE,
        related_name='payments'
    )

    amount = models.DecimalField(max_digits=10, decimal_places=2)
    phone_number = models.CharField(max_length=15)
    transaction_id = models.CharField(max_length=100, unique=True)

    status = models.CharField(
        max_length=20,
        choices=STATUS_CHOICES,
        default='completed'
    )

    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.tenant} - {self.amount}"

    def save(self, *args, **kwargs):
        is_new = self.pk is None

        # 🔥 FORCE UNIT CONSISTENCY
        if self.invoice and not self.unit:
            self.unit = self.invoice.unit

        super().save(*args, **kwargs)

        # 🔥 CRITICAL: KEEP INVOICE SYNCED
        if is_new and self.invoice:
            self.invoice.update_status()

        # OPTIONAL: keep unit-level recalculation safe
        if self.invoice:
            self.invoice.unit.refresh_from_db()

# ================= NOTIFICATION =================
class Notification(models.Model):
    TYPE_CHOICES = (
        ('system', 'System'),
        ('payment', 'Payment'),
        ('rent', 'Rent'),
        ('announcement', 'Announcement'),
    )

    user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='notifications')

    title = models.CharField(max_length=255)
    message = models.TextField()

    notification_type = models.CharField(max_length=20, choices=TYPE_CHOICES, default='system')

    is_read = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    unit = models.ForeignKey(Unit, on_delete=models.SET_NULL, null=True, blank=True)

    def __str__(self):
        return f"{self.user} - {self.title}"


# ================= ANNOUNCEMENTS =================
class Announcement(models.Model):

    FREQUENCY_CHOICES = (
        ("once", "One Time"),
        ("daily", "Daily"),
        ("weekly", "Weekly"),
        ("monthly", "Monthly"),
    )

    AUDIENCE_CHOICES = (
        ("all", "All Tenants"),
        ("filtered", "Filtered"),
    )

    SEND_METHOD_CHOICES = (
        ("in_app", "In App"),
        ("sms", "SMS"),
        ("both", "Both"),
    )

    title = models.CharField(max_length=255)
    message = models.TextField()

    sender = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    audience_type = models.CharField(max_length=20, choices=AUDIENCE_CHOICES, default="all")
    building = models.ForeignKey("properties.Building", on_delete=models.SET_NULL, null=True, blank=True)

    send_method = models.CharField(max_length=20, choices=SEND_METHOD_CHOICES, default="in_app")

    is_automated = models.BooleanField(default=False)
    frequency = models.CharField(max_length=20, choices=FREQUENCY_CHOICES, default="once")

    scheduled_time = models.DateTimeField(null=True, blank=True)

    is_sent = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)


class AnnouncementLog(models.Model):
    announcement = models.ForeignKey(Announcement, on_delete=models.CASCADE)
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)

    delivered_via = models.CharField(max_length=20)
    status = models.CharField(max_length=20, default="sent")

    created_at = models.DateTimeField(auto_now_add=True)


# ================= EXPENSE CATEGORY =================
class ExpenseCategory(models.Model):

    DEFAULT_CATEGORIES = [
        "Water", "Electricity", "Garbage", "Security",
        "Repairs", "Maintenance", "Internet", "Staff",
    ]

    name = models.CharField(max_length=100)
    created_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="expense_categories")
    is_default = models.BooleanField(default=False)

    def __str__(self):
        return self.name


# ================= EXPENSE =================
class Expense(models.Model):

    FREQUENCY_CHOICES = (
        ("daily", "Daily"),
        ("weekly", "Weekly"),
        ("monthly", "Monthly"),
    )

    STATUS_CHOICES = (
        ("pending", "Pending Approval"),
        ("approved", "Approved"),
        ("rejected", "Rejected"),
    )

    building = models.ForeignKey("properties.Building", on_delete=models.CASCADE, related_name="expenses")

    category = models.ForeignKey(ExpenseCategory, on_delete=models.SET_NULL, null=True)

    amount = models.DecimalField(max_digits=10, decimal_places=2)
    description = models.TextField(blank=True)

    frequency = models.CharField(max_length=10, choices=FREQUENCY_CHOICES)

    recorded_by = models.ForeignKey(User, on_delete=models.CASCADE, related_name="recorded_expenses")
    approved_by = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True, related_name="approved_expenses")

    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")

    expense_date = models.DateField(default=timezone.now)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return f"{self.category} - {self.amount} ({self.status})"

    def save(self, *args, **kwargs):
        is_new = self.pk is None
        super().save(*args, **kwargs)

        if is_new:
            landlord = self.building.landlord

            notify_user(
                landlord,
                "New Expense Recorded",
                f"{self.category} expense of KES {self.amount} recorded for {self.building.name}",
                n_type="system"
            )