import { Ref, computed, onMounted, ref, unref, watch } from 'vue';
import { useUserPref } from './userPref.composable';
import { useRoute } from 'vue-router';
import {
  getNumberFromPathQuery,
  saveValuesToPathQuery,
} from '@/helpers/location.helper';

const USER_PREF_PAGINATION = 'pagination-size';
const TABLE_SIZE_KEY = 'table-size';
const TABLE_CURRENT_PAGE_KEY = 'table-page';

export const usePagination = (
  persistent: boolean | Ref<boolean> = true,
  initialSize: number | Ref<number> = 25,
  initialPagination: number[] | Ref<number[]> = [25, 50, 100],
  initialPage: number | Ref<number> = 0,
) => {
  const { getUserPref, saveUserPref } = useUserPref();
  const route = useRoute();

  const items = ref<any[]>([]);
  const pagination = ref<number[]>(unref(initialPagination));
  const reflect = ref<boolean>(unref(persistent));
  const currentInitialPage = ref<number>(unref(initialPage));
  const currentPage = ref<number>(unref(currentInitialPage));
  const size = ref<number>(unref(initialSize));
  const isMounting = ref<boolean>(true);

  const offset = computed(() => currentPage.value * size.value);

  const paginationsOptions = computed(() => [
    ...new Set([...pagination.value, size.value].sort((a, b) => a - b)),
  ]);

  const currentItems = computed(() =>
    size
      ? items.value.slice(offset.value, (currentPage.value + 1) * size.value)
      : items.value,
  );

  const totalPages = computed(() => Math.ceil(items.value.length / size.value));

  watch(size, () => {
    if (reflect.value) {
      saveValuesToPathQuery([
        { key: TABLE_SIZE_KEY, value: size.value.toString() },
      ]);
      saveUserPref(USER_PREF_PAGINATION, size.value, route.path);
    }
  });

  watch(currentPage, () => {
    if (reflect.value) {
      saveValuesToPathQuery([
        {
          key: TABLE_CURRENT_PAGE_KEY,
          value: currentPage.value.toString(),
        },
      ]);
    }
  });

  const goToPage = (index: number, total: number = totalPages.value) => {
    if (total <= 0) {
      return;
    }

    if (index < currentInitialPage.value) {
      currentPage.value = currentInitialPage.value;
      return;
    }

    if (index >= total - 1) {
      currentPage.value = total - 1;
      return;
    }

    currentPage.value = index;
  };

  onMounted(() => {
    if (reflect.value) {
      const savedCurrentPage = getNumberFromPathQuery(TABLE_CURRENT_PAGE_KEY);
      if (savedCurrentPage !== null) {
        currentPage.value = savedCurrentPage;
      }
      const preferedTableSize =
        getNumberFromPathQuery(TABLE_SIZE_KEY) ||
        getUserPref(USER_PREF_PAGINATION, route.path);
      if (preferedTableSize !== undefined && preferedTableSize !== null) {
        size.value = preferedTableSize;
      }
    }
    isMounting.value = false;
  });

  return {
    offset,
    currentPage,
    currentInitialPage,
    pagination,
    size,
    paginationsOptions,
    currentItems,
    items,
    totalPages,
    goToPage,
    isMounting,
  };
};
