from time import sleep
from urllib.parse import quote_plus

from pydoof.management_api.api_client import ManagementAPIClient
from pydoof.management_api.exceptions import TooManyRequestsError


class Scroll:
    @staticmethod
    def __get_url(hashid, name):
        return f"/api/v2/search_engines/{hashid}/indices/{name}/items/"

    def __init__(self, hashid, name, rpp=None, client=None, **opts):
        super().__init__()

        self.scroll_id = None
        self.rpp = rpp

        self.hashid = hashid
        self.name = name

        self.api_client = client or ManagementAPIClient(**opts)

    def __iter__(self):
        scroll_page = self.new()
        while scroll_page["items"]:
            yield from scroll_page["items"]
            scroll_page = self.__next_with_retry()

    def __next_with_retry(self):
        tries = 0
        while True:
            try:
                return self.next()
            except TooManyRequestsError:
                if tries < 3:
                    tries += 1
                    sleep(1)
                else:
                    raise

    @property
    def _query_params(self):
        params = {}
        if self.scroll_id:
            params["scroll_id"] = self.scroll_id
        if self.rpp:
            params["rpp"] = self.rpp
        return params

    def new(self):
        scroll_page = self.api_client.get(self.__get_url(self.hashid, self.name), self._query_params)
        self.scroll_id = scroll_page["scroll_id"]
        return scroll_page

    def next(self):
        return self.api_client.get(self.__get_url(self.hashid, self.name), self._query_params)


def _get_items_url(hashid, name, temp=False):
    url = f"/api/v2/search_engines/{hashid}/indices/{name}"
    if temp:
        url += "/temp"
    return url + "/items"


def _get_item_url(hashid, name, item_id, temp=False):
    url = f"/api/v2/search_engines/{hashid}/indices/{name}"
    if temp:
        url += "/temp"
    return url + f"/items/{quote_plus(item_id)}"


def _get_bulk_url(hashid, name, temp=False):
    url = f"/api/v2/search_engines/{hashid}/indices/{name}"
    if temp:
        url += "/temp"
    return url + "/items/_bulk"


def scroll(hashid, name, rpp=None, **opts):
    return Scroll(hashid, name, rpp, **opts)


def create(hashid, name, item, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.post(_get_items_url(hashid, name, temp), item)


def get(hashid, name, item_id, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.get(_get_item_url(hashid, name, item_id, temp))


def update(hashid, name, item_id, item, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.patch(_get_item_url(hashid, name, item_id, temp), item)


def delete(hashid, name, item_id, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    api_client.delete(_get_item_url(hashid, name, item_id, temp))


def find(hashid, name, items_ids, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.post(_get_items_url(hashid, name, temp) + "/_mget", items_ids)


def bulk_create(hashid, name, items, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.post(_get_bulk_url(hashid, name, temp), items)


def bulk_update(hashid, name, items, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.patch(_get_bulk_url(hashid, name, temp), items)


def bulk_delete(hashid, name, items, temp=False, client=None, **opts):
    api_client = client or ManagementAPIClient(**opts)
    return api_client.delete(_get_bulk_url(hashid, name, temp), items)
