from django.db.models import Value, CharField, F
from django.db.models.functions import Concat, Coalesce, NullIf, Trim


class FullNameSearchMixin:
    """
    Adds a `full_name` annotation and enables searching against it.
    Assumes:
        User -> OneToOne -> UserProfile (related_name='profile')
        profile.first_name
        profile.last_name
    """

    search_param = "search"
    full_name_annotation = "full_name"

    def annotate_full_name(self, queryset):
        """
        full_name priority:
        1. Profile first + last name
        2. Username
        3. "Unknown"
        """

        return queryset.annotate(
            **{
                self.full_name_annotation: Coalesce(
                    NullIf(
                        Trim(
                            Concat(
                                Coalesce(F("profile__first_name"), Value("")),
                                Value(" "),
                                Coalesce(F("profile__last_name"), Value("")),
                            )
                        ),
                        Value("")
                    ),
                    NullIf(F("username"), Value("")),
                    Value("Unknown"),
                    output_field=CharField(),
                )
            }
        )

    def apply_full_name_search(self, queryset):
        search = self.request.query_params.get(self.search_param)
        if not search:
            return queryset
        return queryset.filter(**{
            f"{self.full_name_annotation}__icontains": search
        })
