from decimal import Decimal

from django.core.validators import MinValueValidator, MaxValueValidator
from django.db import models
from django.utils import timezone

from admin_panel.models import User, Investor, Investment, Business


class SoftDeleteModel(models.Model):
    deleted_at = models.DateTimeField(null=True, blank=True, db_index=True)

    class Meta:
        abstract = True

    def soft_delete(self):
        self.deleted_at = timezone.now()
        self.save(update_fields=["deleted_at"])


class Agent(SoftDeleteModel):
    user = models.OneToOneField(
        User, on_delete=models.PROTECT, related_name="agent_profile",
        null=True, blank=True,
    )
    name = models.CharField(max_length=255)
    email = models.EmailField(blank=True)
    mobile = models.CharField(max_length=30, blank=True)
    image = models.ImageField(upload_to="agents/profile/", blank=True, null=True)
    other_details = models.TextField(blank=True)
    created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name="agents_created")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]

    def __str__(self):
        return self.name


class AgentDetailField(models.Model):
    class Sections(models.TextChoices):
        IDENTITY = "IDENTITY", "Identity"
        BANK = "BANK", "Bank"
        NOMINEE = "NOMINEE", "Nominee"

    agent = models.ForeignKey(Agent, on_delete=models.CASCADE, related_name="detail_fields")
    section = models.CharField(max_length=20, choices=Sections.choices)
    key = models.CharField(max_length=100)
    value = models.TextField(blank=True)

    class Meta:
        ordering = ["section", "id"]
        indexes = [models.Index(fields=["agent", "section"])]


class AgentDocument(models.Model):
    class Sections(models.TextChoices):
        IDENTITY = "IDENTITY", "Identity"
        BANK = "BANK", "Bank"
        NOMINEE = "NOMINEE", "Nominee"
        OTHER = "OTHER", "Other"

    agent = models.ForeignKey(Agent, on_delete=models.CASCADE, related_name="uploaded_documents")
    section = models.CharField(max_length=20, choices=Sections.choices, default=Sections.OTHER)
    title = models.CharField(max_length=255)
    file = models.FileField(upload_to="agents/documents/")
    uploaded_by = models.ForeignKey(User, on_delete=models.PROTECT)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]


class AgentInvestmentShare(models.Model):
    """Admin-assigned percentage of an investment's daily investor profit payable to its Agent."""
    agent = models.ForeignKey(Agent, on_delete=models.PROTECT, related_name="investment_shares")
    investment = models.OneToOneField(Investment, on_delete=models.PROTECT, related_name="agent_profit_share")
    profit_percentage = models.DecimalField(
        max_digits=7, decimal_places=4,
        validators=[MinValueValidator(Decimal("0")), MaxValueValidator(Decimal("100"))],
    )
    effective_from = models.DateField(default=timezone.localdate)
    created_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name="agent_profit_shares_created")
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ["-created_at"]


class AgentLedgerEntry(models.Model):
    class EntryTypes(models.TextChoices):
        SOFT_DEBIT = "SOFT_DEBIT", "Soft Debit"
        DEBIT = "DEBIT", "Debit"

    agent = models.ForeignKey(Agent, on_delete=models.PROTECT, related_name="ledger_entries")
    investment = models.ForeignKey(Investment, on_delete=models.PROTECT, related_name="agent_ledger_entries", null=True, blank=True)
    investor = models.ForeignKey(Investor, on_delete=models.PROTECT, related_name="agent_ledger_entries", null=True, blank=True)
    business = models.ForeignKey(Business, on_delete=models.PROTECT, related_name="agent_ledger_entries", null=True, blank=True)
    entry_date = models.DateField(default=timezone.localdate, db_index=True)
    entry_type = models.CharField(max_length=20, choices=EntryTypes.choices)
    amount = models.DecimalField(max_digits=14, decimal_places=2, validators=[MinValueValidator(Decimal("0"))])
    profit_percentage = models.DecimalField(max_digits=7, decimal_places=4, null=True, blank=True)
    description = models.TextField(blank=True)
    reference = models.CharField(max_length=150, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-entry_date", "-created_at"]
        constraints = [
            models.UniqueConstraint(
                fields=["investment", "entry_date", "entry_type"],
                condition=models.Q(investment__isnull=False, entry_type="SOFT_DEBIT"),
                name="unique_agent_soft_debit_per_investment_day",
            )
        ]


class AgentPayout(models.Model):
    class Status(models.TextChoices):
        REQUESTED = "REQUESTED", "Requested"
        PAID = "PAID", "Paid"
        REJECTED = "REJECTED", "Rejected"

    agent = models.ForeignKey(Agent, on_delete=models.PROTECT, related_name="payouts")
    amount = models.DecimalField(max_digits=14, decimal_places=2, validators=[MinValueValidator(Decimal("0.01"))])
    payout_date = models.DateField(default=timezone.localdate)
    notes = models.TextField(blank=True)
    status = models.CharField(max_length=20, choices=Status.choices, default=Status.REQUESTED)
    requested_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name="agent_payouts_requested")
    processed_by = models.ForeignKey(User, on_delete=models.PROTECT, related_name="agent_payouts_processed", null=True, blank=True)
    processed_at = models.DateTimeField(null=True, blank=True)
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ["-created_at"]
