import datetime

from django.db.models import Func, F, Value, Case, When, DecimalField, Q
from django.db.models.functions import Extract
from django.utils import timezone

from apps.currencies.models import Currency
from apps.currencies.models import ExchangeRate


def get_exchange_rate(
    from_currency: Currency, to_currency: Currency, date: datetime.date
) -> ExchangeRate | None:
    try:
        exchange_rate = (
            ExchangeRate.objects.filter(
                Q(from_currency=from_currency, to_currency=to_currency)
                | Q(from_currency=to_currency, to_currency=from_currency)
            )
            .annotate(
                date_diff=Func(
                    Extract(F("date") - Value(date), "epoch"), function="ABS"
                ),
                effective_rate=Case(
                    When(from_currency=from_currency, then=F("rate")),
                    default=1 / F("rate"),
                    output_field=DecimalField(),
                ),
            )
            .order_by("date_diff")
            .first()
        )

        if exchange_rate is None:
            return None

    except ExchangeRate.DoesNotExist:
        return None

    else:
        return exchange_rate


def convert(amount, from_currency: Currency, to_currency: Currency, date=None):
    if from_currency == to_currency:
        return None, None, None, None

    if amount == 0:
        return None, None, None, None

    if date is None:
        date = timezone.localtime(timezone.now())

    exchange_rate = get_exchange_rate(
        from_currency=from_currency, to_currency=to_currency, date=date
    )

    if exchange_rate is None:
        return None, None, None, None

    return (
        amount * exchange_rate.effective_rate,
        to_currency.prefix,
        to_currency.suffix,
        to_currency.decimal_places,
    )
