import { atom } from 'jotai';
import { SearchParams, SearchResult } from 'src/application/models/api/search';
import { ProductSorting } from './types';
import { ProductFilters } from './productFilters';
import { ProductSorter } from './productSorter';
import { newOrgConfigAtom } from '../org';
import { getSearchServiceFunction } from './searchServiceAdapter';

export type SelectedFilterOption = {
  id: string; // "filterId:filterItemId" - maintains backward compatibility for comparisons
  displayName: string;
  filterId: string; // Filter category
  filterItemId: string; // Filter value
};

interface SearchState {
  data: SearchResult | null;
  loading: boolean;
  error: string | null;
  lastQuery: string | null;
}

export const searchAtom = atom<SearchState>({
  data: null,
  loading: false,
  error: null,
  lastQuery: null,
});

export const searchProductSortingAtom = atom<ProductSorting>(ProductSorting.FEATURED);
export const searchSelectedFiltersAtom = atom<SelectedFilterOption[]>([]);

export const createFilterOption = (
  filterId: string,
  filterItemId: string,
  displayName: string,
): SelectedFilterOption => ({
  id: `${filterId}:${filterItemId}`,
  displayName,
  filterId,
  filterItemId,
});

const internalSearchParamsAtom = atom<{
  id: string | null;
  query: string | null;
}>({
  id: null,
  query: null,
});

export const searchParamsAtom = atom(
  get => get(internalSearchParamsAtom),
  (_, set, value: { id: string | null; query: string | null }) => {
    set(internalSearchParamsAtom, value);
  },
);
export const internalSearchSystemStateAtom = atom<boolean>(false);

export const searchSystemAtom = atom(
  get => get(internalSearchSystemStateAtom),
  (get, set, value: boolean) => {
    if (value === get(internalSearchSystemStateAtom)) {
      return;
    }
    const stateChangeHandler = () => {
      const params = new URLSearchParams(window.location.search);
      if (params.get('es') === 'true') {
        const id = params.get('esi');
        const query = params.get('esq');
        set(searchParamsAtom, { id, query });
      } else {
        set(searchParamsAtom, { id: null, query: null });
      }
    };
    if (value) {
      set(internalSearchSystemStateAtom, true);
      window.addEventListener('popstate', stateChangeHandler);
      // Also trigger the hash change handler to set the initial state
      stateChangeHandler();
    } else {
      set(internalSearchSystemStateAtom, false);
      window.removeEventListener('popstate', stateChangeHandler);
    }
  },
);

export const filteredSearchProductsAtom = atom(get => {
  const searchData = get(searchAtom).data;
  const sorting = get(searchProductSortingAtom);
  const selectedFilters = get(searchSelectedFiltersAtom);
  const newOrgConfig = get(newOrgConfigAtom);

  if (!searchData?.products || !newOrgConfig?.frontendConfig?.uiConfigs?.searchConfig) return [];

  const filteredProducts = ProductFilters.filterProducts(
    searchData.products,
    newOrgConfig.frontendConfig.uiConfigs.searchConfig.searchFilterConfig,
    selectedFilters,
    newOrgConfig.frontendConfig.uiConfigs.searchConfig.additiveDynamicFilters,
  );

  return ProductSorter.sort(filteredProducts, sorting);
});

export const searchFiltersAtom = atom(get => {
  const searchData = get(searchAtom).data;
  const selectedFilters = get(searchSelectedFiltersAtom);
  const newOrgConfig = get(newOrgConfigAtom);

  if (!searchData?.products || !newOrgConfig?.frontendConfig?.uiConfigs?.searchConfig) return [];

  return ProductFilters.getFiltersForProducts(
    searchData.products,
    newOrgConfig.frontendConfig.uiConfigs.searchConfig.searchFilterConfig,
    selectedFilters,
  );
});

export const addSearchFilterAtom = atom(null, (get, set, filter: SelectedFilterOption) => {
  const current = get(searchSelectedFiltersAtom);
  if (!current.some(f => f.id === filter.id)) {
    set(searchSelectedFiltersAtom, [...current, filter]);
  }
});

export const removeSearchFilterAtom = atom(null, (get, set, filterId: string) => {
  const current = get(searchSelectedFiltersAtom);
  set(
    searchSelectedFiltersAtom,
    current.filter(f => f.id !== filterId),
  );
});

export const clearSearchFiltersAtom = atom(null, (_, set) => {
  set(searchSelectedFiltersAtom, []);
});

export const performSearchAtom = atom(
  null,
  async (get, set, params: SearchParams, allowRedirect = false) => {
    const currentState = get(searchAtom);
    const newOrgConfig = get(newOrgConfigAtom);
    const redirectSearchResultsUrl =
      newOrgConfig?.frontendConfig?.uiConfigs?.searchConfig?.redirectSearchResultsUrl;

    if (allowRedirect && redirectSearchResultsUrl) {
      const redirectUrl = new URL(redirectSearchResultsUrl);
      redirectUrl.searchParams.set('es', 'true');
      redirectUrl.searchParams.set('esq', params.query);
      window.location.href = redirectUrl.toString();
    } else {
      // Update URL and manually trigger state change (since pushState doesn't trigger popstate)
      const url = new URL(window.location.href);
      url.searchParams.set('es', 'true');
      url.searchParams.set('esq', params.query);
      window.history.pushState({}, '', url);

      // Manually trigger page variant re-evaluation by dispatching a popstate event
      // This ensures the page variant system detects the URL change and mounts search results
      window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
    }

    // Manually trigger page variant re-evaluation by dispatching a popstate event
    // This ensures the page variant system detects the URL change and mounts search results
    window.dispatchEvent(new PopStateEvent('popstate', { state: {} }));
    if (currentState.loading) {
      return; // Prevent concurrent searches
    }

    set(searchAtom, {
      data: null,
      loading: true,
      error: null,
      lastQuery: params.query,
    });
    try {
      const searchServiceFunction = getSearchServiceFunction();
      const result = await searchServiceFunction(params);
      set(searchAtom, {
        data: result,
        loading: false,
        error: null,
        lastQuery: params.query,
      });
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : 'An unknown error occurred';
      set(searchAtom, {
        data: null,
        loading: false,
        error: errorMessage,
        lastQuery: params.query,
      });
    }
  },
);
