import uuid

from django.conf import settings
from django.db import models


class TimeStampedModel(models.Model):
    """Abstract base model with created/updated tracking for audit purposes."""

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)
    created_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.DO_NOTHING,  # cross-db for tenant apps; deleting a user shouldn't touch other DBs
        null=True,
        blank=True,
        related_name="%(app_label)s_%(class)s_created",
        db_constraint=False,  # may live in a different physical DB (tenant apps)
    )
    updated_by = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.DO_NOTHING,  # cross-db for tenant apps; deleting a user shouldn't touch other DBs
        null=True,
        blank=True,
        related_name="%(app_label)s_%(class)s_updated",
        db_constraint=False,  # may live in a different physical DB (tenant apps)
    )

    class Meta:
        abstract = True


class Project(TimeStampedModel):
    """A construction / partnership project. Everything else hangs off this,
    so the system can manage more than one joint-venture project at once."""

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    name = models.CharField(max_length=255)
    location = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    start_date = models.DateField(null=True, blank=True)
    total_land_area = models.CharField(max_length=100, blank=True, help_text="e.g. 5 Katha")
    is_active = models.BooleanField(default=True)
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, blank=True,
        related_name="owned_projects",
    )
    database_key = models.CharField(
        max_length=100, blank=True, null=True, unique=True,
        help_text="Internal company database key.",
    )
    database_name = models.CharField(max_length=64, blank=True)
    database_user = models.CharField(max_length=64, blank=True)
    database_password_encrypted = models.TextField(
        blank=True,
        help_text="Legacy encrypted password field, kept for backward compatibility. No longer written to.",
    )
    database_password = models.CharField(
        max_length=255, blank=True,
        help_text="Stored in plain text at explicit request. See README for the security tradeoff this implies.",
    )
    database_host = models.CharField(max_length=255, default="127.0.0.1")
    database_port = models.PositiveIntegerField(default=3306)
    DATABASE_STATUS_CHOICES = [
        ("pending", "Pending"),
        ("provisioned", "Provisioned"),
        ("failed", "Failed"),
    ]
    database_status = models.CharField(max_length=20, choices=DATABASE_STATUS_CHOICES, default="pending")
    database_error = models.TextField(blank=True)
    database_provisioned_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        db_table = "core_project"
        ordering = ["-created_at"]

    def __str__(self):
        return self.name

    # ---- rollup helpers used by the dashboard ----
    def total_members(self):
        return self.members.filter(is_active=True).count()

    def total_contribution(self):
        from contributions.models import Contribution
        return Contribution.objects.filter(member__project=self).aggregate(
            total=models.Sum("amount")
        )["total"] or 0

    def total_expense(self):
        from expenses.models import Expense
        return Expense.objects.filter(project=self).aggregate(
            total=models.Sum("amount")
        )["total"] or 0


class AuditLog(models.Model):
    """Immutable, append-only record of who changed what and when.
    This is the 'suspicion killer' feature called out in the spec:
    every create / update / delete on a tracked model is logged here."""

    ACTION_CHOICES = [
        ("create", "Created"),
        ("update", "Updated"),
        ("delete", "Deleted"),
    ]

    id = models.BigAutoField(primary_key=True)
    project = models.ForeignKey(
        Project, on_delete=models.SET_NULL, null=True, blank=True, related_name="audit_logs"
    )
    user = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.SET_NULL, null=True, related_name="audit_logs"
    )
    action = models.CharField(max_length=10, choices=ACTION_CHOICES)
    model_name = models.CharField(max_length=100)
    object_id = models.CharField(max_length=64)
    object_repr = models.CharField(max_length=255)
    changes = models.JSONField(default=dict, blank=True)
    timestamp = models.DateTimeField(auto_now_add=True)
    ip_address = models.GenericIPAddressField(null=True, blank=True)

    class Meta:
        db_table = "core_audit_log"
        ordering = ["-timestamp"]
        indexes = [
            models.Index(fields=["model_name", "object_id"]),
            models.Index(fields=["-timestamp"]),
        ]

    def __str__(self):
        who = self.user.get_full_name() or self.user.username if self.user else "System"
        return f"{who} {self.action} {self.model_name} #{self.object_id}"


class ProjectMembership(models.Model):
    """Connects a user to one project with a project-specific role."""
    ROLE_CHOICES = [
        ("admin", "Admin"),
        ("accountant", "Accountant"),
        ("member", "Member"),
        ("viewer", "Viewer"),
    ]
    project = models.ForeignKey(Project, on_delete=models.CASCADE, related_name="memberships")
    user = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="project_memberships")
    role = models.CharField(max_length=20, choices=ROLE_CHOICES, default="viewer")
    is_active = models.BooleanField(default=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = "core_project_membership"
        constraints = [
            models.UniqueConstraint(fields=["project", "user"], name="unique_project_user_membership")
        ]

    def __str__(self):
        return f"{self.project} / {self.user} / {self.get_role_display()}"


class ProjectApplication(models.Model):
    STATUS_CHOICES = [
        ("pending", "Pending"),
        ("approved", "Approved"),
        ("paused", "Paused"),
        ("deleted", "Deleted"),
    ]
    applicant = models.ForeignKey(
        settings.AUTH_USER_MODEL, on_delete=models.CASCADE, related_name="project_applications"
    )
    project_name = models.CharField(max_length=255)
    location = models.CharField(max_length=255, blank=True)
    description = models.TextField(blank=True)
    start_date = models.DateField(null=True, blank=True)
    total_land_area = models.CharField(max_length=100, blank=True)
    status = models.CharField(max_length=20, choices=STATUS_CHOICES, default="pending")
    approved_project = models.OneToOneField(
        Project, on_delete=models.SET_NULL, null=True, blank=True, related_name="application"
    )
    created_at = models.DateTimeField(auto_now_add=True)
    reviewed_at = models.DateTimeField(null=True, blank=True)

    class Meta:
        db_table = "core_project_application"
        ordering = ["-created_at"]

    def __str__(self):
        return f"{self.project_name} — {self.applicant.get_full_name() or self.applicant.username}"
