import { deserializeWithContextAndRun, FilterQueryParams, isSerializedFunction, mergeObjects, SerializedFunction } from '@win2win/shared';
import { set } from 'lodash';
import { computed, ComputedRef, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import { DynamicTableViewsRefs } from '../../models';
import { useContextParams } from './useContextParams';

export const DEFAULT_FILTERS: FilterQueryParams = {
  terms: '',
  bycol: {},
  byEqualCol: {},
  byNotEqualCol: {},
  byGreaterCol: {},
  byLessCol: {},
  byBetweenCol: {},
  custom: {},
};

export const DEFAULT_ROWS_PER_PAGE = 10;
export const DEFAULT_PAGINATION: QTablePagination = {
  page: 1,
  rowsNumber: 0,
  rowsPerPage: DEFAULT_ROWS_PER_PAGE,
  sortBy: '',
  descending: true,
};

export function useQueryParams(refs: ComputedRef<DynamicTableViewsRefs>) {
  const filters = ref<FilterQueryParams>(DEFAULT_FILTERS);
  const pagination = ref<QTablePagination>(DEFAULT_PAGINATION);
  const route = useRoute();
  const currentPath = computed(() => route.path);
  const filtersStoreKey = computed(() => `${currentPath.value}_${refs.value.idGama}_FILTERS`);
  const paginationStoreKey = computed(() => `${currentPath.value}_${refs.value.idGama}_PAGINATION`);
  const { contextParams } = useContextParams();

  const storedFiltersJoined = ref(false);
  const storedPaginationJoined = ref(false);

  const setQueryParams = (evt) => {
    const { filter: _filter, pagination: _pagination } = evt;
    pagination.value = _pagination;
    filters.value = mergeObjects(filters.value, _filter);
  };

  const deserializeIfNeeded = (stringFnOrObject?: Record<string, any> | SerializedFunction | null) => {
    if (isSerializedFunction(stringFnOrObject)) {
      return deserializeWithContextAndRun(stringFnOrObject as SerializedFunction, contextParams.value);
    }
    if (typeof stringFnOrObject === 'object') {
      return stringFnOrObject;
    }
    return {};
  };

  const resetQueryParams = () => {
    storedFiltersJoined.value = false;
    filters.value = { ...DEFAULT_FILTERS, custom: { idGama: refs.value.idGama } };
    pagination.value = { ...DEFAULT_PAGINATION, rowsPerPage: DEFAULT_ROWS_PER_PAGE };
  };

  watch(
    () => refs.value.layout,
    (layoutValue) => {
      const keysToCompareTerms = layoutValue?.query?.keysToCompareTerms;
      const customFilters = refs.value.customConfig?.queryParams || {};
      const baseFilters = mergeObjects(deserializeIfNeeded(layoutValue?.query?.baseQueryParams), customFilters);
      const storedFilters = storedFiltersJoined.value ? {} : JSON.parse(localStorage.getItem(filtersStoreKey.value) || '{}');
      filters.value = mergeObjects<FilterQueryParams>(filters.value, storedFilters, { ...baseFilters, keysToCompareTerms });
      storedFiltersJoined.value = true;

      const initialPagination = deserializeIfNeeded(layoutValue?.query?.initialPagination);
      const storedPagination = storedPaginationJoined.value ? {} : JSON.parse(localStorage.getItem(paginationStoreKey.value) || '{}');
      pagination.value = mergeObjects<QTablePagination>(pagination.value, initialPagination, storedPagination);
      storedPaginationJoined.value = true;
    },
    {
      immediate: true,
    }
  );

  watch(
    pagination,
    (val) => {
      if (!storedPaginationJoined.value) return;
      localStorage.setItem(paginationStoreKey.value, JSON.stringify(val));
    },
    { deep: true }
  );

  watch(
    filters,
    (val) => {
      if (!storedFiltersJoined.value) return;
      localStorage.setItem(filtersStoreKey.value, JSON.stringify(val));
    },
    { deep: true }
  );

  watch(
    () => refs.value.customConfig?.queryParams,
    (value) => {
      filters.value = mergeObjects<FilterQueryParams>(filters.value, value || {});
    },
    {
      immediate: true,
      deep: true,
    }
  );

  watch(
    () => refs.value.idGama,
    (value) => {
      set(filters.value, ['custom', 'idGama'], value);
    },
    { immediate: true }
  );

  watch(
    () => route.fullPath,
    () => {
      resetQueryParams();
    }
  );

  return { filters, pagination, setQueryParams };
}

export interface QTablePagination {
  sortBy: string;
  descending: boolean;
  page: number;
  rowsPerPage: number;
  rowsNumber: number;
}
