import logging
import traceback
from typing import Any

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.utils.translation import gettext_lazy as _

from engine.payments.gateways import BadLimitsError
from engine.payments.models import Balance, Gateway, Transaction
from engine.payments.utils.emailing import balance_deposit_email
from engine.vibes_auth.models import User

logger = logging.getLogger(__name__)


# noinspection PyUnusedLocal
@receiver(post_save, sender=User)
def create_balance_on_user_creation_signal(
    instance: User, created: bool, **kwargs: dict[Any, Any]
) -> None:
    if created:
        Balance.objects.create(user=instance)


# noinspection PyUnusedLocal
@receiver(post_save, sender=Transaction)
def process_transaction_changes(
    instance: Transaction, created: bool, **kwargs: dict[Any, Any]
) -> None:
    if created:
        if not instance.gateway:
            instance.gateway = Gateway.objects.can_be_used().first()
        try:
            gateway = instance.gateway.get_integration_class_object()
            if (
                instance.gateway.minimum_transaction_amount
                <= instance.amount
                <= instance.gateway.maximum_transaction_amount
            ):
                gateway.process_transaction(instance)
            else:
                raise BadLimitsError(
                    _(
                        f"the transaction amount didn't fit into allowed limits: "
                        f"{instance.gateway.minimum_transaction_amount} "
                        f"!<= {instance.amount} "
                        f"!<= {instance.gateway.maximum_transaction_amount}"
                    )
                )
        except Exception as e:
            instance.process = {"status": "ERRORED", "error": str(e)}
            logger.error(
                f"Error processing transaction {instance.uuid}: {e}\n{traceback.format_exc()}"
            )
    if not created:
        status = str(instance.process.get("status", "")).lower()
        success = instance.process.get("success", False)

        if ("success" in status or success) and (instance.process.get("notify", False)):
            balance_deposit_email.delay(str(instance.uuid))
