import { PageStore } from '../../../../utils/stores/';
import { formatInnerLink, getRequest } from '../../../../utils/helpers/';

export function ItemsListHandler(
  itemsPerPage,
  maxItems,
  first_item_request_url,
  request_url,
  itemsCountCallback,
  loadItemsCallback
) {
  const config = {
    maxItems: maxItems || 255,
    pageItems: itemsPerPage ? Math.min(maxItems, itemsPerPage) : 1,
  };

  const state = {
    totalItems: 0,
    totalPages: 0,
    nextRequestUrl: formatInnerLink(request_url, PageStore.get('config-site').url),
  };

  const waiting = {
    pageItems: 0,
    requestResponse: false,
  };

  let firstItemUrl = null;

  const items = [];
  const responseItems = [];

  const callbacks = {
    itemsCount: function () {
      if ('function' === typeof itemsCountCallback) {
        itemsCountCallback(state.totalItems);
      }
    },
    itemsLoad: function () {
      if ('function' === typeof loadItemsCallback) {
        loadItemsCallback(items);
      }
    },
  };

  function loadNextItems(itemsLength) {
    let itemsToLoad, needExtraRequest;

    itemsLength = !isNaN(itemsLength) ? itemsLength : config.pageItems;

    if (waiting.pageItems && waiting.pageItems <= responseItems.length) {
      itemsToLoad = waiting.pageItems;
      needExtraRequest = false;
      waiting.pageItems = 0;
    } else {
      itemsToLoad = Math.min(itemsLength, responseItems.length);
      needExtraRequest = itemsLength > responseItems.length && !!state.nextRequestUrl;
      waiting.pageItems = needExtraRequest ? itemsLength - responseItems.length : 0;
    }

    if (itemsToLoad) {
      let i = 0;
      while (i < itemsToLoad) {
        items.push(responseItems.shift());
        i += 1;
      }
      callbacks.itemsLoad();
    }

    if (needExtraRequest) {
      runRequest();
    }
  }

  function runFirstItemRequest() {
    function fn(response) {
      if (!!!response || !!!response.data) {
      } else {
        let data = response.data;
        let results = void 0 !== data.results ? data.results : data; // NOTE: The structure of response data in case of categories differs from the others.

        if (results.length) {
          firstItemUrl = results[0].url;
          items.push(results[0]);
        }
      }

      runRequest(true);
    }

    getRequest(formatInnerLink(first_item_request_url, PageStore.get('config-site').url), false, fn);
  }

  function runRequest(initialRequest) {
    waiting.requestResponse = true;

    function fn(response) {
      waiting.requestResponse = false;

      if (!!!response || !!!response.data) {
        return;
      }

      let data = response.data;
      let results = void 0 !== data.results ? data.results : data; // NOTE: The structure of response data in case of categories differs from the others.

      let i = 0;
      while (i < results.length && config.maxItems > responseItems.length) {
        if (null === firstItemUrl || firstItemUrl !== results[i].url) {
          responseItems.push(results[i]);
        }
        i += 1;
      }

      state.nextRequestUrl = !!data.next && config.maxItems > responseItems.length ? data.next : null;

      if (initialRequest) {
        // In some cases, (total) 'count' field is missing, but probably doesn't need (eg. in recommended media).
        state.totalItems = !!data.count ? data.count : responseItems.length;
        state.totalItems = Math.min(config.maxItems, state.totalItems);

        state.totalPages = Math.ceil(state.totalItems / config.pageItems);

        callbacks.itemsCount();
      }

      loadNextItems();
    }

    getRequest(state.nextRequestUrl, false, fn);

    state.nextRequestUrl = null;
  }

  function loadItems(itemsLength) {
    if (!waiting.requestResponse && items.length < state.totalItems) {
      loadNextItems(itemsLength);
    }
  }

  function totalPages() {
    return state.totalPages;
  }

  function loadedAllItems() {
    return items.length === state.totalItems;
  }

  function cancelAll() {
    itemsCountCallback = null;
    loadItemsCallback = null;
  }

  if (void 0 !== first_item_request_url && null !== first_item_request_url) {
    runFirstItemRequest();
  } else {
    runRequest(true);
  }

  return {
    loadItems,
    totalPages,
    loadedAllItems,
    cancelAll,
  };
}
