import { useEffect, useMemo, useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import {
  KEY_CATEGORY,
  KEY_LOCATION,
  KEY_COMPANY,
  KEY_PAGE,
  KEY_SEARCH,
  KEY_SORTBY,
  KEY_SUBCATEGORY,
} from "../../constants/queryStringConstants";
import { fetchCategories } from "../../store/actions/categories/categoriesActions";
import { fetchLocations } from "../../store/actions/locations/locationsActions";
import {
  selectOffers,
  selectPinnedOffers,
  selectTotalOffers,
} from "../../store/selectors/offersSelectors";
import useFilters from "./useFilters";
import useQueryString from "./useQueryString";
import { setQueryString } from "../../store/actions/queryString/queryStringActions";
import {
  convertQueryStringForBackend,
  makeHeaderStringFromQueryObjectHelper,
  makeHeaderStringHelper,
  makeQueryStringHelper,
} from "../../util/helpers/queryHelpers";
import useSorting from "./useSorting";
import useSearch from "./useSearch";
import {
  setHeaderString,
  setSearchString,
} from "../../store/actions/filters/filtersActions";
import usePaging from "./usePaging";
import { useHistory } from "react-router-dom";

const useOffers = () => {
  const dispatch = useDispatch();

  const apply = () => {
    filters.apply();
    const newQueryString = makeQueryStringHelper(
      filters,
      paging,
      search,
      sorting
    );
    dispatch(setQueryString(convertQueryStringForBackend(newQueryString)));
  };

  const filters = useFilters(false, apply);
  const queryStringHook = useQueryString();
  const pinnedOffers = useSelector(selectPinnedOffers);
  const offers = useSelector(selectOffers);
  const totalOffers = useSelector(selectTotalOffers);
  const history = useHistory();
  const [filtersCleared, setFiltersCleared] = useState(false);

  // Always fetch categories and locations,
  // becouse count of total offers change over time
  useEffect(() => {
    dispatch(fetchCategories());
    dispatch(fetchLocations());
    return () => clear();
  }, []);

  useEffect(() => {
    if (!queryStringHook.historyStateCleared && history.location.state) {
      clearFiltersAndApply();
      dispatch(setHeaderString(makeHeaderStringHelper({})));
      history.location.state = {};
    }
  }, [history.location]);

  // On every change of query string, new header string should be created
  // Header string is shown on Home page above offers
  useEffect(() => {
    const headerStringLocal = makeHeaderStringHelper(filters);
    dispatch(setHeaderString(headerStringLocal));
  }, [queryStringHook.queryString, filtersCleared]);

  // Initially set category, location and subcategory based on query string
  useEffect(() => {
    if (queryStringHook.isInitiallyLoaded) {
      const queryObject = queryStringHook.queryObject;
      if (KEY_CATEGORY in queryObject) {
        const category = filters.category.findCategory(
          queryObject[KEY_CATEGORY]
        );
        filters.category.setSelectedCategory(category);
        if (KEY_SUBCATEGORY in queryObject) {
          const subcategory = filters.category
            .getSubcategories(category?.name)
            .find(
              (subcategory) => subcategory.name === queryObject[KEY_SUBCATEGORY]
            );
          filters.subcategory.setSelectedSubcategory(subcategory);
        }
      }
      if (KEY_LOCATION in queryObject) {
        filters.locations.setSelectedLocationsFromArray(
          queryObject[KEY_LOCATION]
        );
      }
      if (KEY_COMPANY in queryObject) {
        filters.companies.setSelectedCompaniesFromArray(
          queryObject[KEY_COMPANY]
        );
      }
      if (KEY_SORTBY in queryObject) {
        sorting.changeSortingFromName(queryObject[KEY_SORTBY]);
      }
      if (KEY_PAGE in queryObject) {
        if (queryObject[KEY_PAGE] !== 1)
          paging.changePage(queryObject[KEY_PAGE]);
      }
      if (KEY_SEARCH in queryObject) {
        search.searchOffers(queryObject[KEY_SEARCH]);
      } else {
        search.clear();
      }
      dispatch(setSearchString(queryObject[KEY_SEARCH]));
      dispatch(
        setHeaderString(makeHeaderStringFromQueryObjectHelper(queryObject))
      );
    }
  }, [queryStringHook.isInitiallyLoaded]);

  const allOffersToShow = useMemo(() => {
    return [...pinnedOffers, ...offers];
  }, [offers, pinnedOffers]);

  useEffect(() => {
    if (filtersCleared) {
      setFiltersCleared(false);
      apply();
    }
  }, [filtersCleared]);

  const applyFilters = () => {
    setFiltersCleared(true);
  };
  
  const clearFiltersAndApply = () => {
    clear();
    setFiltersCleared(true);
  };
  
  const applySorting = () => {
    paging.changePage(1);
    setFiltersCleared(true);
  };
  
  const applySearch = () => {
    paging.changePage(1);
    setFiltersCleared(true);
  };

  // Those hooks are below becouse function apply cannot be put on props before initialization
  const sorting = useSorting(applySorting);
  const paging = usePaging(apply);
  const search = useSearch(applySearch);

  // On every change of search string, offers should be immediately searched
  useEffect(() => {
    if (queryStringHook.isInitiallyLoaded) {
      search.searchOffers(search.searchString);
    }
  }, [search.searchString]);

  // Clears only filters(does not clear sorting and search)
  const clearOnlyFiltersAndApply = () => {
    filters.clear();
    paging.changePage(1);
    setFiltersCleared(true);
  };

  const clear = () => {
    filters.clear();
    sorting.clear();
    paging.changePage(1);
    search.clear();
  };

  return {
    filters,
    sorting,
    paging,
    search,
    queryStringHook,
    allOffersToShow,
    totalOffers,
    applyFilters,
    clearFiltersAndApply,
    clearOnlyFiltersAndApply,
    apply,
    clear,
  };
};

export default useOffers;
