import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import { RefObject, useCallback, useEffect, useMemo, useRef } from 'react';

import {
  SelectedFilterOption,
  addSearchFilterAtom,
  clearSearchFiltersAtom,
  createFilterOption,
  filteredSearchProductsAtom,
  performSearchAtom,
  removeSearchFilterAtom,
  searchAtom,
  searchFiltersAtom,
  searchParamsAtom,
  searchProductSortingAtom,
  searchSelectedFiltersAtom,
} from 'src/atoms/search';
import { isFilterOpenAtom } from 'src/atoms/globalSearch/globalSearch';
import { formatFilterDisplayName } from 'src/atoms/search/utils';
import { ProductSorting } from 'src/atoms/search/types';
import { useAmplitude } from 'src/contexts/amplitudeContext/amplitudeContext';
import { SpiffyMetricsEventName } from 'src/services/amplitudeService/amplitudeService';
import { SpiffyWidgets } from 'src/application/models/spiffyWidgets';
import { ProductCardConfig } from 'src/contexts/types';
import { SearchResult } from 'src/application/models/api/search';
import { SearchResponseProduct } from '@spiffy-ai/commerce-api-client';
import { SearchFilterDatum, SelectFilterItem } from 'src/types/search-filter-types';
import { orgShortNameAtom } from 'src/atoms/envive/enviveConfig';
import { FrontendConfig, SearchResponseProductAttributes } from 'src/application/models';
import { useIntersection } from 'src/hooks/Intersection/useIntersection';
import { SearchResultsState, getSearchResultsState } from '../utils';
import { useSearchInput } from './useSearchInput';
import { useNewOrgConfig } from '../NewOrgConfig';
import { useRecommendedProducts } from './useRecommendedProducts';

export interface SearchResultsHocProps {
  // Data
  searchData: SearchResult | null;
  searchResponseId: string;
  merchantShortName: string;
  productCardConfig: ProductCardConfig;
  productList: SearchResponseProduct[];
  autocompleteResults: string[];
  searchFilters: SearchFilterDatum[];
  availableDynamicFilters: { name: string; displayName: string }[];
  selectedFilterOptions: SelectedFilterOption[];
  recommendedProducts: SearchResponseProductAttributes['attributes'][];
  recommendedProductsHeading: string;
  searchOverlayHeading: string;

  // State
  searchText: string;
  query: string;
  searchResultsState: SearchResultsState;
  isLoadingSearch: boolean;
  isFilterOpen: boolean;
  shouldShowAutocomplete: boolean;
  focusedIndex: number;
  focusedOptionId: string | undefined;

  // UI
  filterButtonText: string;

  // Event Handlers
  onSearchInputChange: (value: string) => void;
  onSubmitSearch: () => void;
  onAutocompleteSelect: (suggestion: string) => void;
  onKeyDown: (event: React.KeyboardEvent<HTMLInputElement>) => void;
  onSearchInputFocus: () => void;
  onSearchInputBlur: () => void;
  onToggleDynamicFilter: ({
    filter,
    dynamicFilterDisplayName,
  }: {
    filter: string;
    dynamicFilterDisplayName: string;
  }) => void;
  onSelectFilterItem: SelectFilterItem;
  onRemoveFilter: (filter: SelectedFilterOption) => void;
  onClearAllFilters: () => void;
  setIsFilterOpen: (isFilterOpen: boolean) => void;
  resetSearch: () => void;
  // Refs
  searchResultsRef: React.RefObject<HTMLDivElement>;
}

export const useSearch = ({
  allowRedirect = false,
}: { allowRedirect?: boolean } = {}): SearchResultsHocProps => {
  // Atoms
  const config = useNewOrgConfig();
  const orgShortName = useAtomValue(orgShortNameAtom);
  const { data: searchData, loading: isLoadingSearch } = useAtomValue(searchAtom);
  const productList = useAtomValue(filteredSearchProductsAtom);
  const performSearch = useSetAtom(performSearchAtom);
  const [{ query }] = useAtom(searchParamsAtom);
  const [isFilterOpen, setIsFilterOpen] = useAtom(isFilterOpenAtom);
  const [selectedFilterOptions] = useAtom(searchSelectedFiltersAtom);
  const addFilter = useSetAtom(addSearchFilterAtom);
  const removeFilter = useSetAtom(removeSearchFilterAtom);
  const [productSorting, setProductSorting] = useAtom(searchProductSortingAtom);
  const clearFilters = useSetAtom(clearSearchFiltersAtom);
  const searchFilters = useAtomValue(searchFiltersAtom);
  const recommendedProducts = useRecommendedProducts();

  // Refs
  const searchResultsRef = useRef<HTMLDivElement>(null);

  // Utilities
  const scrollToTop = useCallback(() => {
    const container = searchResultsRef.current;
    if (container) {
      container.scrollTo({ top: 0, behavior: 'smooth' });
    } else {
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }
  }, []);

  // Search Input Hook
  const searchInput = useSearchInput({
    initialSearchText: '',
    searchOrigin: SpiffyWidgets.SearchResults,
    onSearchSubmit: searchQuery => {
      performSearch({ query: searchQuery }, allowRedirect);
    },
  });

  const {
    searchText,
    focusedIndex,
    focusedOptionId,
    autocompleteResults,
    shouldShowAutocomplete,
    handleSearchInputChange,
    handleSearchInputFocus,
    handleSearchInputBlur,
    handleKeyDown,
    handleAutocompleteSelect,
    handleSubmitSearch,
    setSearchText,
    resetSearch,
  } = searchInput;
  const searchResultsState = getSearchResultsState(isLoadingSearch, searchData);

  const dynamicFilters = searchData?.filters || [];

  // Provide fallback values when orgUIConfig is not yet available
  const safeProductCardConfig = (config?.frontendConfig as FrontendConfig)?.uiConfigs
    ?.productCardConfig || {
    variant: 'minimal',
    hoverVariant: 'none',
    layoutVariant: 'square',
  };
  const safeMerchantShortName = orgShortName || '';
  const searchConfig = config?.frontendConfig?.uiConfigs?.searchConfig;
  const safeRecommendedProductsHeading =
    searchConfig?.recommendedProductsHeading || 'Suggested Products';
  const safeSearchOverlayHeading =
    searchConfig?.searchOverlayHeading ?? 'What can I help you find?';
  const availableDynamicFilters = useMemo(() => {
    return dynamicFilters
      .filter(
        dynamicFilterName =>
          !selectedFilterOptions.some(option => option.id === `dynamic:${dynamicFilterName}`),
      )
      .map(dynamicFilterName => ({
        name: dynamicFilterName,
        displayName: formatFilterDisplayName(dynamicFilterName),
      }));
  }, [dynamicFilters, selectedFilterOptions]);

  const filters = useMemo(() => {
    const sortOptions = [
      {
        filterItemId: String(ProductSorting.FEATURED),
        displayName: 'Relevance',
        productCount: 0,
        isSelected: productSorting === ProductSorting.FEATURED,
      },
      {
        filterItemId: String(ProductSorting.PRICE_ASC),
        displayName: 'Price: Low to High',
        productCount: 0,
        isSelected: productSorting === ProductSorting.PRICE_ASC,
      },
      {
        filterItemId: String(ProductSorting.PRICE_DESC),
        displayName: 'Price: High to Low',
        productCount: 0,
        isSelected: productSorting === ProductSorting.PRICE_DESC,
      },
    ];

    return [
      { filterId: 'sort', displayName: 'SORT', items: sortOptions },
      ...searchFilters,
    ] as SearchFilterDatum[];
  }, [productSorting, searchFilters]);

  const filterButtonText = useMemo(() => {
    const selectedCount = filters.reduce((acc: number, filter) => {
      if (filter.filterId === 'sort') {
        return acc;
      }
      return acc + filter.items.filter(item => item.isSelected).length;
    }, 0);
    if (selectedCount === 0) {
      return 'Filter & Sort';
    }
    return `Filter & Sort (${selectedCount})`;
  }, [filters]);

  // Callbacks
  const { trackEvent } = useAmplitude();

  const handleToggleDynamicFilter = useCallback(
    ({
      filter,
      dynamicFilterDisplayName,
    }: {
      filter: string;
      dynamicFilterDisplayName: string;
    }) => {
      trackEvent({
        eventName: SpiffyMetricsEventName.SearchFilterClicked,
        eventProps: {
          filterType: 'Dynamic',
          filterValue: filter,
          queryText: searchText,
        },
      });
      addFilter(createFilterOption('dynamic', filter, dynamicFilterDisplayName));
      scrollToTop();
    },
    [addFilter, searchText, scrollToTop],
  );

  const handleRemoveFilter = useCallback(
    (filter: SelectedFilterOption) => {
      removeFilter(filter.id);
      scrollToTop();
    },
    [removeFilter, scrollToTop],
  );

  const handleSelectFilterItem: SelectFilterItem = useCallback(
    ({
      filterId,
      filterItemId,
      isSelected,
      displayName,
    }: {
      filterId: string;
      filterItemId: string;
      isSelected: boolean;
      displayName: string;
    }) => {
      if (filterId === 'sort') {
        const newSort = filterItemId as ProductSorting;
        trackEvent({
          eventName: SpiffyMetricsEventName.SearchSortClicked,
          eventProps: {
            sortType: newSort,
            queryText: searchText,
          },
        });
        setProductSorting(newSort);
        scrollToTop();
      } else if (!isSelected) {
        removeFilter(`${filterId}:${filterItemId}`);
        scrollToTop();
      } else {
        trackEvent({
          eventName: SpiffyMetricsEventName.SearchFilterClicked,
          eventProps: {
            filterType: 'Static',
            filterCategory: filterId,
            filterValue: filterItemId,
            queryText: searchText,
          },
        });
        addFilter(createFilterOption(filterId, filterItemId, displayName));
        scrollToTop();
      }
    },
    [addFilter, removeFilter, setProductSorting, searchText, scrollToTop],
  );

  const handleClearAllFilters = useCallback(() => {
    setProductSorting(ProductSorting.FEATURED);
    clearFilters();
    scrollToTop();
  }, [setProductSorting, clearFilters, scrollToTop]);

  const searchResultsVisible = useIntersection(searchResultsRef as RefObject<HTMLElement>, '0px');
  const hasTrackedSearchComponentVisible = useRef(false);

  useEffect(() => {
    if (!searchResultsVisible || hasTrackedSearchComponentVisible.current) {
      return;
    }
    hasTrackedSearchComponentVisible.current = true;
    trackEvent({
      eventName: SpiffyMetricsEventName.SearchComponentVisible,
      eventProps: {},
    });
  }, [searchResultsVisible, trackEvent]);

  useEffect(() => {
    if (
      searchResultsState === SearchResultsState.Results ||
      searchResultsState === SearchResultsState.NoResults
    ) {
      trackEvent({
        eventName: SpiffyMetricsEventName.SearchResultsViewed,
        eventProps: {
          queryText: searchText,
          resultsCount: productList.length,
        },
      });
    }
  }, [productList.length, searchResultsState]);

  // This is the single source of truth for the search text triggering a search
  useEffect(() => {
    if (query && query !== searchText) {
      const esq = new URLSearchParams(window.location.search).get('esq');
      setSearchText(query);
      performSearch({ query: esq ?? query });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [performSearch, query, setSearchText]);

  return {
    searchData,
    searchResponseId: searchData?.searchResponseId ?? '',
    merchantShortName: safeMerchantShortName,
    recommendedProductsHeading: safeRecommendedProductsHeading,
    searchOverlayHeading: safeSearchOverlayHeading,
    productCardConfig: safeProductCardConfig,
    productList,
    recommendedProducts,
    autocompleteResults,
    searchFilters: filters,
    availableDynamicFilters,
    selectedFilterOptions,
    searchText,
    query: query || '',
    searchResultsState,
    isLoadingSearch,
    isFilterOpen,
    shouldShowAutocomplete,
    focusedIndex,
    focusedOptionId,
    filterButtonText,
    onSearchInputChange: handleSearchInputChange,
    onSubmitSearch: handleSubmitSearch,
    onAutocompleteSelect: handleAutocompleteSelect,
    onKeyDown: handleKeyDown,
    onSearchInputFocus: handleSearchInputFocus,
    onSearchInputBlur: handleSearchInputBlur,
    onToggleDynamicFilter: handleToggleDynamicFilter,
    onSelectFilterItem: handleSelectFilterItem,
    onRemoveFilter: handleRemoveFilter,
    onClearAllFilters: handleClearAllFilters,
    setIsFilterOpen,
    resetSearch,
    searchResultsRef: searchResultsRef as RefObject<HTMLDivElement>,
  };
};
