# apps/shares/models.py
from django.db import models, transaction
from django.utils import timezone
from django.utils.translation import gettext_lazy as _
from apps.core.models import BaseModel, AuditLog, Notification
from apps.members.models import Member
from apps.banking.models import Transaction, Account, TransactionCategory


class ShareType(BaseModel):
    """Définit un type de part sociale avec sa valeur nominale."""

    name = models.CharField(
        max_length=100, unique=True, verbose_name=_("Nom du type de part")
    )
    nominal_value = models.DecimalField(
        max_digits=10, decimal_places=2, verbose_name=_("Valeur nominale")
    )

    def __str__(self):
        return self.name

    class Meta(BaseModel.Meta):
        verbose_name = _("Type de part sociale")
        verbose_name_plural = _("Types de parts sociales")
        db_table = "shares_share_type"


class ShareSubscription(BaseModel):
    """Représente la souscription d'un membre à un certain nombre de parts sociales."""

    member = models.ForeignKey(
        Member,
        on_delete=models.CASCADE,
        related_name="subscriptions",
        verbose_name=_("Membre"),
    )
    share_type = models.ForeignKey(
        ShareType, on_delete=models.PROTECT, verbose_name=_("Type de part")
    )
    subscribed_quantity = models.PositiveIntegerField(
        verbose_name=_("Quantité souscrite")
    )
    subscription_date = models.DateField(
        auto_now_add=True, verbose_name=_("Date de souscription")
    )

    @property
    def paid_quantity(self):
        """Calcule le nombre de parts déjà libérées pour cette souscription."""
        from django.db.models import Sum

        return self.payments.aggregate(total=Sum("paid_quantity"))["total"] or 0

    @property
    def is_fully_paid(self):
        """Vérifie si la souscription est entièrement libérée."""
        return self.paid_quantity >= self.subscribed_quantity

    def __str__(self):
        return f"Souscription de {self.subscribed_quantity} parts de {self.share_type} par {self.member}"

    @transaction.atomic
    def make_payment(self, quantity, by_user, from_account):
        """Enregistre un paiement pour un certain nombre de parts de cette souscription."""
        if self.is_fully_paid:
            raise ValueError("Cette souscription est déjà entièrement libérée.")

        unpaid_quantity = self.subscribed_quantity - self.paid_quantity
        if quantity > unpaid_quantity:
            raise ValueError(
                f"Vous ne pouvez pas payer plus de parts qu'il n'en reste à libérer ({unpaid_quantity})."
            )

        try:
            to_account = Account.objects.get(type=Account.AccountType.SHARE_CAPITAL)
        except (Account.DoesNotExist, Account.MultipleObjectsReturned):
            raise ValueError(
                "Le compte de capital social est introuvable ou mal configuré."
            )

        amount = quantity * self.share_type.nominal_value
        financial_transaction = Transaction.objects.create(
            from_account=from_account,
            to_account=to_account,
            amount=amount,
            category=TransactionCategory.SHARE_PAYMENT,
            description=f"Paiement de {quantity} part(s) pour la souscription {self.id}",
            created_by=by_user,
        )

        SharePayment.objects.create(
            subscription=self,
            paid_quantity=quantity,
            financial_transaction=financial_transaction,
            created_by=by_user,
        )

        AuditLog.objects.create(
            user=by_user,
            action_type=AuditLog.ActionType.TRANSACTION,
            content_object=self,
            description=f"Paiement de {quantity} part(s) ({amount}) reçu pour la souscription {self.id}.",
        )

        Notification.objects.create(
            recipient=self.member.user,
            title="Confirmation de paiement de parts sociales",
            message=f"Votre paiement de {amount} pour {quantity} part(s) de type '{self.share_type.name}' a été reçu avec succès.",
            notification_type=Notification.NotificationType.SUCCESS,
        )

    class Meta(BaseModel.Meta):
        verbose_name = _("Souscription de part sociale")
        verbose_name_plural = _("Souscriptions de parts sociales")
        db_table = "shares_share_subscription"


class SharePayment(BaseModel):
    """Représente un paiement effectué pour libérer des parts souscrites."""

    subscription = models.ForeignKey(
        ShareSubscription,
        on_delete=models.CASCADE,
        related_name="payments",
        verbose_name=_("Souscription"),
    )
    paid_quantity = models.PositiveIntegerField(verbose_name=_("Quantité payée"))
    financial_transaction = models.OneToOneField(
        Transaction,
        on_delete=models.PROTECT,
        related_name="share_payment",
        verbose_name=_("Transaction financière"),
    )

    @property
    def amount_paid(self):
        """Retourne le montant payé via la transaction financière associée."""
        return self.financial_transaction.amount

    def __str__(self):
        return f"Paiement de {self.paid_quantity} parts pour {self.subscription}"

    class Meta(BaseModel.Meta):
        verbose_name = _("Paiement de part sociale")
        verbose_name_plural = _("Paiements de parts sociales")
        db_table = "shares_share_payment"
