from urllib.parse import parse_qsl

from graphene import Boolean, Field, Int, JSONString, List, ObjectType, String

from dictionary.templatetags.filters import humanize_count
from dictionary.utils.managers import TopicListManager
from dictionary.utils.serializers import LeftFrame
from dictionary_graph.types import CategoryType


class Topic(ObjectType):
    title = String()
    slug = String()
    count = String()


class Paginator(ObjectType):
    num_pages = Int()
    page_range = List(Int)


class Page(ObjectType):
    has_next = Boolean()
    has_other_pages = Boolean()
    has_previous = Boolean()
    number = Int()
    object_list = List(Topic)
    paginator = Field(Paginator)


class Tab(ObjectType):
    name = String()
    safename = String()


class Exclusions(ObjectType):
    active = List(String)
    available = List(CategoryType)


class Tabs(ObjectType):
    current = String()
    available = List(Tab)


class Extra(ObjectType):
    name = String()
    value = String()


class TopicList(ObjectType):
    page = Field(Page)
    parameters = String()
    refresh_count = Int()
    year = Int()
    year_range = List(Int)
    safename = String()
    slug = String()
    slug_identifier = String()
    tabs = Field(Tabs)
    exclusions = Field(Exclusions)
    extra = List(Extra)


class TopicListQuery(ObjectType):
    topics = Field(
        TopicList,
        slug=String(required=True),
        year=Int(),
        page=Int(),
        search_keys=String(),
        refresh=Boolean(),
        tab=String(),
        exclusions=List(String),
        extra=JSONString(),
    )

    @staticmethod
    def resolve_topics(_parent, info, slug, **kwargs):
        # Convert string query parameters to actual dictionary to use it in TopicListHandler
        search_keys = dict(parse_qsl(kwargs.get("search_keys"))) if kwargs.get("search_keys") else {}
        manager = TopicListManager(
            slug,
            info.context.user,
            kwargs.get("year"),
            search_keys,
            kwargs.get("tab"),
            kwargs.get("exclusions"),
            extra=kwargs.get("extra"),
        )

        if kwargs.get("refresh"):
            manager.delete_cache(delimiter=True)

        frame = LeftFrame(manager, kwargs.get("page"))
        page = frame.page  # May raise PermissionDenied or Http404

        object_list = [
            Topic(title=t["title"], slug=t["slug"], count=humanize_count(t.get("count"))) for t in page["object_list"]
        ]

        paginator = {"num_pages": page["paginator"]["num_pages"], "page_range": page["paginator"]["page_range"]}

        tabs = (
            Tabs(
                current=frame.tabs["current"],
                available=[Tab(name=key, safename=value) for key, value in frame.tabs["available"].items()],
            )
            if frame.tabs
            else None
        )

        exclusions = (
            Exclusions(active=frame.exclusions["active"], available=frame.exclusions["available"])
            if frame.exclusions
            else None
        )

        extra = [Extra(name=key, value=value) for key, value in frame.extra.items()] if frame.extra else None

        page_data = {
            "has_next": page.get("has_next"),
            "has_other_pages": page.get("has_other_pages"),
            "has_previous": page.get("has_previous"),
            "number": page.get("number"),
            "object_list": object_list,
            "paginator": Paginator(**paginator),
        }

        data = {
            "page": Page(**page_data),
            "parameters": frame.parameters,
            "refresh_count": frame.refresh_count,
            "year": frame.year,
            "year_range": frame.year_range,
            "safename": frame.safename,
            "slug": frame.slug,
            "slug_identifier": frame.slug_identifier,
            "tabs": tabs,
            "exclusions": exclusions,
            "extra": extra,
        }

        return TopicList(**data)
