from decimal import Decimal

from django.db.models import QuerySet, Sum
from wbcore import viewsets
from wbcore.utils.strings import format_number

from wbaccounting.models import BookingEntry
from wbaccounting.models.booking_entry import BookingEntryType
from wbaccounting.serializers import (
    BookingEntryModelSerializer,
    BookingEntryRepresentationSerializer,
    BookingEntryTypeModelSerializer,
    BookingEntryTypeRepresentationSerializer,
)
from wbaccounting.viewsets.buttons import BookingEntryButtonConfig
from wbaccounting.viewsets.display import BookingEntryDisplayConfig
from wbaccounting.viewsets.titles import BookingEntryTitleConfig


class BookingEntryTypeRepresentationViewSet(viewsets.RepresentationViewSet):
    search_fields = ["key", "title"]
    ordering_fields = ["title"]
    ordering = ["title"]
    serializer_class = BookingEntryTypeRepresentationSerializer
    queryset = BookingEntryType.objects.all()


class BookingEntryRepresentationViewSet(viewsets.RepresentationViewSet):
    search_fields = ["counterparty__computed_str", "title", "currency__key"]
    ordering_fields = ["title"]
    ordering = ["title"]
    serializer_class = BookingEntryRepresentationSerializer
    queryset = BookingEntry.objects.all()

    def get_queryset(self):
        return BookingEntry.objects.filter_for_user(self.request.user)


class BookingEntryTypeModelViewSet(viewsets.ModelViewSet):
    search_fields = ["key", "title"]
    ordering_fields = ["title"]
    ordering = ["title"]
    serializer_class = BookingEntryTypeModelSerializer
    queryset = BookingEntryType.objects.all()


class BookingEntryModelViewSet(viewsets.ModelViewSet):
    filterset_fields = {
        "counterparty": ["exact"],
        "booking_date": ["gte", "exact", "lte"],
        "reference_date": ["gte", "exact", "lte"],
    }
    search_fields = ["counterparty__computed_str", "title", "currency__key"]
    ordering_fields = (
        "counterparty__computed_str",
        "booking_date",
        "gross_value",
        "net_value",
        "reference_date",
    )
    ordering = ["-booking_date"]

    serializer_class = BookingEntryModelSerializer
    queryset = BookingEntry.objects.all()

    button_config_class = BookingEntryButtonConfig
    display_config_class = BookingEntryDisplayConfig
    title_config_class = BookingEntryTitleConfig

    def get_aggregates(self, queryset, paginated_queryset):
        if not queryset.exists():
            return {}

        return {
            "net_value": {"Σ": format_number(queryset.aggregate(s=Sum("net_value"))["s"] or Decimal("0"), decimal=8)},
            "gross_value": {
                "Σ": format_number(queryset.aggregate(s=Sum("gross_value"))["s"] or Decimal("0"), decimal=8)
            },
            "invoice_net_value": {
                "Σ": format_number(queryset.aggregate(s=Sum("invoice_net_value"))["s"] or Decimal("0"), decimal=8)
            },
            "invoice_gross_value": {
                "Σ": format_number(queryset.aggregate(s=Sum("invoice_gross_value"))["s"] or Decimal("0"), decimal=8)
            },
        }

    def get_queryset(self) -> QuerySet[BookingEntry]:
        booking_entries = BookingEntry.objects.filter_for_user(self.request.user)

        if eai_id := self.kwargs.get("entry_accounting_information_id", None):
            booking_entries = booking_entries.filter(counterparty__entry_accounting_information__id=eai_id)

        if invoice_id := self.kwargs.get("invoice_id", None):
            booking_entries = booking_entries.filter(invoice_id=invoice_id)

        return booking_entries.select_related(
            "counterparty",
            "invoice",
            "product",
            "type",
            "account",
            "currency",
            "invoice__invoice_currency",
        )
