from ast import literal_eval
from typing import Any, TYPE_CHECKING
from rest_framework.serializers import BaseSerializer

if TYPE_CHECKING:
    from ..viewsets import LCGenericViewSet

    ViewsetBase = LCGenericViewSet
else:
    ViewsetBase = object


# ---------------------------------------------------------------------------
class DataTablesMixin(ViewsetBase):
    """
    Methods to support DataTables serializers on ModelViewsSets
    """

    datatables_serializer: type[BaseSerializer] | None = None

    def is_datatables(self) -> bool:
        try:
            return self.request.accepted_renderer.format == 'datatables'
        except AttributeError:
            return False

    def get_serializer_class(self) -> type[BaseSerializer]:
        if self.is_datatables() and self.datatables_serializer:
            return self.datatables_serializer
        return super().get_serializer_class()

    def get_value(self, key: str, default: Any) -> str:
        """
        Check for key in either the POST data or Query Params.
        POST data takes precedence over Query Params.
        """
        try:
            if self.request.data and key in self.request.data:
                val = self.request.data[key]
            elif self.request.query_params and key in self.request.query_params:
                val = self.request.query_params[key]
            else:
                val = default
        except AttributeError:
            return default

        try:
            return literal_eval(val)
        except ValueError:
            return val

    def get_serializer_context(self) -> dict:
        """
        Add data to context from POST data and query params.
        """
        context = super().get_serializer_context()
        allowed_fields = self.get_value(key='allowed_fields', default=[])

        if allowed_fields:
            context['allowed_fields'] = allowed_fields

        return context


# ---------------------------------------------------------------------------
class SelectFieldMixin(ViewsetBase):
    """
    Methods to support handy data backend for HTML Select fields
    """

    selectfield_serializer: type[BaseSerializer] | None = None

    def is_selectfield(self) -> bool:
        try:
            return self.request.accepted_renderer.format in ('selectfield', 'apiselectfield')
        except AttributeError:
            return False

    def get_serializer_class(self):
        if self.is_selectfield() and self.selectfield_serializer:
            return self.selectfield_serializer
        return super().get_serializer_class()


__all__ = (
    'DataTablesMixin',
    'SelectFieldMixin',
)
