# apps/banking/models.py
from django.db import models
from django.conf import settings
from django.utils.translation import gettext_lazy as _
from apps.core.models import BaseModel


class Account(BaseModel):
    """
    Modèle représentant un compte financier dans le système.
    Hérite de BaseModel pour l'audit et l'ID unique.
    """

    class AccountType(models.TextChoices):
        CURRENT = "CURRENT", _("Compte Courant")
        SAVINGS = "SAVINGS", _("Compte Épargne")
        SHARE_CAPITAL = "SHARE_CAPITAL", _("Capital Social")
        SOLIDARITY_FUND = "SOLIDARITY_FUND", _("Fonds de Solidarité")
        RESERVE_FUND = "RESERVE_FUND", _("Fonds de Réserve")
        CASH_DESK = "CASH_DESK", _("Caisse de Guichet")
        MOBILE_MONEY = "MOBILE_MONEY", _("Mobile Money")
        LOAN_FUND = "LOAN_FUND", _("Fonds de Prêt")
        INTEREST_INCOME = "INTEREST_INCOME", _("Revenus d'Intérêts")
        LOAN_LOSS_RESERVE = "LOAN_LOSS_RESERVE", _("Réserve pour Créances Douteuses")

    # id est hérité de BaseModel
    owner = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.CASCADE,
        null=True,
        blank=True,
        related_name="accounts",
        verbose_name=_("Propriétaire"),
    )
    account_manager = models.ForeignKey(
        settings.AUTH_USER_MODEL,
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="managed_accounts",
        limit_choices_to={"is_staff": True},
        verbose_name=_("Gestionnaire de Compte"),
    )
    name = models.CharField(max_length=255, verbose_name=_("Nom du compte"))
    type = models.CharField(
        max_length=20, choices=AccountType.choices, verbose_name=_("Type de compte")
    )
    balance = models.DecimalField(
        max_digits=15, decimal_places=2, default=0, verbose_name=_("Solde")
    )
    iban = models.CharField(
        max_length=34, unique=True, blank=True, null=True, verbose_name=_("IBAN")
    )
    account_number = models.CharField(
        max_length=50,
        unique=True,
        blank=True,
        null=True,
        verbose_name=_("Numéro de Compte"),
    )

    def __str__(self):
        return f"{self.name} ({self.get_type_display()})"

    def save(self, *args, **kwargs):
        """Génère automatiquement un numéro de compte si pas fourni."""
        if not self.account_number:
            self.account_number = self.generate_account_number()
        super().save(*args, **kwargs)

    def generate_account_number(self):
        """Génère un numéro de compte unique basé sur le type."""
        type_prefixes = {
            self.AccountType.CASH_DESK: "CASH",
            self.AccountType.SHARE_CAPITAL: "CAPT",
            self.AccountType.SOLIDARITY_FUND: "SOLID",
            self.AccountType.MOBILE_MONEY: "MOBILE",
            self.AccountType.LOAN_FUND: "LOAN",
            self.AccountType.RESERVE_FUND: "RESRV",
            self.AccountType.SAVINGS: "SAV",
            self.AccountType.LOAN_LOSS_RESERVE: "LLRES",
            self.AccountType.CURRENT: "CURR",
            self.AccountType.INTEREST_INCOME: "INTINC",
        }

        prefix = type_prefixes.get(self.type, "GEN")

        # Compter les comptes existants du même type pour générer un numéro unique
        existing_count = Account.objects.filter(type=self.type).count()
        number = str(existing_count + 1).zfill(3)  # Ex: 001, 002, etc.

        return f"AMIFOND-{prefix}-{number}"

    class Meta(BaseModel.Meta):
        verbose_name = _("Compte")
        verbose_name_plural = _("Comptes")
        db_table = "banking_account"


class TransactionCategory(models.TextChoices):
    """Catégories pour classifier les transactions financières."""

    DEPOSIT = "deposit", _("Dépôt")
    WITHDRAWAL = "withdrawal", _("Retrait")
    TRANSFER = "transfer", _("Virement")
    FEE = "fee", _("Frais")
    INTEREST = "interest", _("Intérêts")
    PENALTY = "penalty", _("Pénalité")
    CORRECTION = "correction", _("Correction")
    OPENING = "opening", _("Ouverture")
    CLOSING = "closing", _("Fermeture")
    SOLIDARITY_FUND = "solidarity_fund", _("Fonds de Solidarité")
    CREDIT = "credit", _("Crédit")
    DEBIT = "debit", _("Débit")
    SHARE_SUBSCRIPTION = "share_subscription", _("Souscription de Parts")
    SHARE_PAYMENT = "share_payment", _("Paiement de Parts")
    SHARE_TRANSFER = "share_transfer", _("Transfert de Parts")
    SHARE_REDEMPTION = "share_redemption", _("Rachat de Parts")
    DIVIDEND_PAYMENT = "dividend_payment", _("Paiement de Dividende")
    MEMBERSHIP_FEE = "membership_fee", _("Frais d'Adhésion")
    FOUNDER_PAYMENT = "founder_payment", _("Paiement Fondateur")
    FOUNDER_DIVIDEND = "founder_dividend", _("Dividende Fondateur")
    LOAN_DISBURSEMENT = "loan_disbursement", _("Décaissement de Prêt")
    LOAN_REPAYMENT = "loan_repayment", _("Remboursement de Prêt")
    LOAN_INTEREST = "loan_interest", _("Intérêts sur Prêt")
    LOAN_PENALTY = "loan_penalty", _("Pénalité de Prêt")
    LOAN_FEE = "loan_fee", _("Frais de Prêt")
    SYSTEM = "system", _("Système")
    ADMINISTRATIVE = "administrative", _("Administration")


class Transaction(BaseModel):
    """
    Modèle représentant une transaction financière entre deux comptes.
    Hérite de BaseModel pour l'audit et l'ID unique.
    """

    # id est hérité de BaseModel
    from_account = models.ForeignKey(
        Account,
        on_delete=models.PROTECT,
        related_name="outgoing_transactions",
        verbose_name=_("Compte source"),
    )
    to_account = models.ForeignKey(
        Account,
        on_delete=models.PROTECT,
        related_name="incoming_transactions",
        verbose_name=_("Compte destination"),
    )
    amount = models.DecimalField(
        max_digits=15, decimal_places=2, verbose_name=_("Montant")
    )
    description = models.CharField(max_length=255, verbose_name=_("Description"))
    transaction_date = models.DateTimeField(
        auto_now_add=True, verbose_name=_("Date de transaction")
    )
    category = models.CharField(
        max_length=50,
        choices=TransactionCategory.choices,
        verbose_name=_("Catégorie de Transaction"),
    )

    def __str__(self):
        # Utiliser created_at de BaseModel au lieu de transaction_date pour l'affichage
        return f"{self.created_at.strftime('%Y-%m-%d %H:%M')}: {self.amount} de {self.from_account} à {self.to_account} ({self.get_category_display()})"

    class Meta(BaseModel.Meta):
        verbose_name = _("Transaction")
        verbose_name_plural = _("Transactions")
        db_table = "banking_transaction"
