<script>
import { ref } from 'vue';
import axios from "axios";
import {API_URL} from "@/main.js";
import { parseError, clearErrors } from "@/components/request/HandleGlobalError.vue";
import {watch} from "vue";

/** The list of items to paginate */
export const list = ref([]);

/** The meta for the list */
export const metaCurrentPage = ref(1) // The current page
export const metaItemsPerPage = ref(100) // The number of items per page
export const metaTotalItems = ref(0); // The total number of items
export const metaSearch = ref(null); // The search query string
export const filter = ref(null); // The filter (eg. department_id or user_id)
export const lastUpdated = ref(null); // The last updated time
export const endpoint = ref(null); // The endpoint
export const meta = ref(null); // The meta object returned from the API
export const orderBy = ref(null); // The order by (eg. id)
export const orderDirection = ref(null); // The order direction (eg. asc)
export const hideSearchField = ref(false); // Hide the search field

/**
 * Set the hide search field
 * @param hide true or false
 */
export const setHideSearchField = (hide) => {
  hideSearchField.value = hide;
};

/** Set the order */
export const setOrder = (column, direction) => {
  orderBy.value = column;
  orderDirection.value = direction;
};

export const setEndpoint = (newEndpoint, autoLoad = true) => {
  endpoint.value = newEndpoint;
  // Reset the errors
  clearErrors();
  // Reset the page to 1
  setPage(1);
  // Clear the list
  list.value = [];
  // Reset the search
  metaSearch.value = null;
  // Reset the meta
  meta.value = null;
  // Reset the filter
  filter.value = null;
  // Reset the order
  setOrder('id', 'asc');
  // Reset the items per page
  metaItemsPerPage.value = 100;
  // Load the list (If the endpoint is set)
  if (autoLoad) {
    loadList();
  }
};

/** Set the last updated time */
export const setLastUpdated = () => {
  lastUpdated.value = new Date();
};

/** The pagination functions */
export const setList = (newList) => {
  list.value = newList;
  setLastUpdated();
};

export const setMeta = (currentPage, itemsPerPage, totalItems) => {
  metaCurrentPage.value = currentPage;
  metaItemsPerPage.value = itemsPerPage;
  metaTotalItems.value = totalItems;
  setLastUpdated();
};

export const setMetaItemsPerPage = (newItemsPerPage, autoload = true) => {
  metaItemsPerPage.value = newItemsPerPage;
  // Reset the page to 1
  setPage(1);
  // Load the list
  if (autoload) {
    loadList();
  }
};

/**
 * Set the filter
 * @param newFilter eg. department_id
 * @param value eg. 3
 * @param autoLoad
 */
export const setFilter = (newFilter, value, autoLoad = true) => {
  if (value === '*') {
    // Remove the filter if the value is *
    filter.value = filter.value ? filter.value.split(',').filter(f => !f.startsWith(`${newFilter}:`)).join(',') : null;
  } else if (filter.value && filter.value.includes(`${newFilter}:`)) {
    // If the filter is already set, replace the value
    filter.value = filter.value.split(',').map(f => f.startsWith(`${newFilter}:`) ? `${newFilter}:${value}` : f).join(',');
  } else {
    // If the filter is not set, add it to the filter
    filter.value = filter.value ? `${filter.value},${newFilter}:${value}` : `${newFilter}:${value}`;
  }
  // Remove duplicates
  filter.value = [...new Set(filter.value.split(','))].join(',');
  // If the filter is empty, set it to null
  if (filter.value === '') {
    filter.value = null;
  }
  // Reset the page to 1
  setPage(1);
  // Load the list (If the endpoint is set)
  if (autoLoad) {
    loadList();
  }
};

/**
 * Search function
 * @param search
 * @param autoLoad BE AWARE, if autoLoad is set to false, you need to call loadList() manually, but the page will be set to 1 automatically!!!
 */
export const search = (search, autoLoad = true) => {
  // If the search is *, remove the search
  metaSearch.value = search === '*' ? null : search;
  // Reset the page to 1
  setPage(1);
  // Load the list
  if (autoLoad) {
    loadList();
  }
};

/** Is the list empty */
export const isEmpty = () => {
  return list.value.length === 0;
};

/** Has the list been loaded */
export const isLoaded = () => {
  return lastUpdated.value !== null;
};

/** Set the page */
export const setPage = (page) => {
  // Make sure the page is within the bounds, if not, return
  if (page < 1 || page > Math.ceil(metaTotalItems.value / metaItemsPerPage.value)) {
    return;
  }
  metaCurrentPage.value = page;
};

/** Set the loading state */
export const isLoading = ref(false);

/** The load switch */
export const loadSwitch = (bool) => {
  isLoading.value = bool;
};

/** The latest search */
export const latestSearch = ref(null);

/** The paginated get request */
export const paginatedGetRequest = async () => {
  // Set the latest search
  latestSearch.value = metaSearch.value;
  const tmp_search = metaSearch.value;
  const token = localStorage.getItem('token');
  if (!token) {
    return null;
  }
  axios.get(API_URL + endpoint.value, {
    params: {
      page: metaCurrentPage.value,
      limit: metaItemsPerPage.value,
      search: metaSearch.value,
      filters: filter.value,
      order: `${orderBy.value}:${orderDirection.value}`
    },
    headers: {
      Authorization: `Bearer ${token}`
    }
  }) .then((response) => {
    // Check if the search is the latest search
    if (!isLatestSearch(tmp_search)) {
      return;
    }
    setList(response.data.data);
    setMeta(response.data.meta.pagination.page, response.data.meta.pagination.per_page, response.data.meta.pagination.total);
    console.log(response.data.meta.pagination.total, 'total');
    meta.value = response.data.meta;
    loadSwitch(false);
    setLastUpdated();
  }).catch((error) => {
    parseError(error, 'paginatedGetRequest');
    console.log(error);
    loadSwitch(false);
  });
};

/**
 * isLatestSearch
 * This function is used to check if the search is the latest search,
 * It is used to prevent the results from being overwritten by an older search
 * @param search
 * @returns {boolean}
 */
export const isLatestSearch = (search) => {
  return search === latestSearch.value;
};


/** The load list function */
export const loadList = () => {
  loadSwitch(true);
  // clear the list
  list.value = [];
  paginatedGetRequest();
};

/**
 * Get filter
 * @param filter
 * @returns {string|null}
 */
export const getFilter = (filter) => {
  if (filter.value && filter.value.includes(`${filter}:`)) {
    return filter.value.split(',').find(f => f.startsWith(`${filter}:`)).split(':')[1];
  }
  return null;
};
</script>