import wagtail.api.v2.serializers as wagtail_serializers
from rest_framework.fields import SerializerMethodField

from vbv_lernwelt.learnpath.utils import get_wagtail_type


def get_it_serializer_class(
    model, field_names=None, base_field_names=None, base_class=None
):
    if field_names is None:
        field_names = []

    if base_field_names is None:
        base_field_names = [
            "id",
            "title",
            "slug",
            "content_type",
            "translation_key",
            "frontend_url",
        ]

    if base_class is None:
        base_class = ItWagtailBaseSerializer

    return wagtail_serializers.get_serializer_class(
        model,
        field_names=base_field_names + field_names,
        meta_fields=[],
        base=base_class,
    )


class ItWagtailTypeField(wagtail_serializers.TypeField):
    def to_representation(self, obj):
        name = get_wagtail_type(obj)
        return name


class ItWagtailBaseSerializer(wagtail_serializers.BaseSerializer):
    content_type = ItWagtailTypeField(read_only=True)
    children = SerializerMethodField()
    frontend_url = SerializerMethodField()

    meta_fields = []

    def __init__(self, *args, **kwargs):
        self.descendants = kwargs.pop("descendants", None)
        super().__init__(*args, **kwargs)

    def get_children(self, obj):
        if not self.descendants:
            self.descendants = [p for p in obj.get_descendants().specific()]
        children = _get_children(self.descendants, obj)
        return [
            c.specific.get_serializer_class()(
                c.specific, descendants=self.descendants
            ).data
            for c in children
        ]

    def get_frontend_url(self, obj):
        if hasattr(obj, "get_frontend_url"):
            return obj.get_frontend_url()
        return ""


def _get_descendants(pages, obj):
    return [c for c in pages if c.path.startswith(obj.path) and c.depth >= obj.depth]


def _get_children(pages, obj):
    return [
        c for c in pages if c.path.startswith(obj.path) and obj.depth + 1 == c.depth
    ]
