import { useEffect, useMemo, useRef, useState } from 'react';
import { useContentCatalogPayload } from '@/business/content-catalog/hooks';
import { CONTENT_CATALOG_TYPES } from '@/shared/constants/contentCatalog';
import {
  VOCATIONAL_CATEGORY_ICON_KEYS,
  VOCATIONAL_CATEGORY_PREVIEW_LIMIT,
  VOCATIONAL_CATEGORY_STYLE_CLASSES,
  VOCATIONAL_SEARCH_DELAY_MS,
} from '@/shared/constants/vocational';
import type {
  VocationalCategoryPreview,
  VocationalCategoryFilter,
  VocationalOpportunity,
} from '@/shared/types/vocational';
import {
  calculateVocationalStats,
  filterVocationalOpportunities,
  listVocationalCategories,
  normalizeVocationalZipCode,
  searchVocationalOpportunitiesByZip,
  toVocationalCategoryFilter,
} from '@/business/vocational/selectors';

export function useVocationalOpportunities() {
  const contentCatalog = useContentCatalogPayload<readonly VocationalOpportunity[]>(
    CONTENT_CATALOG_TYPES.vocationalOpportunities,
    [],
  );
  const searchTimeoutRef = useRef<number | null>(null);
  const [zipCode, setZipCode] = useState('');
  const [searchQuery, setSearchQuery] = useState('');
  const [categoryFilter, setCategoryFilter] = useState<VocationalCategoryFilter>('all');
  const [expandedOpportunityId, setExpandedOpportunityId] = useState<string | null>(null);
  const [savedOpportunityIds, setSavedOpportunityIds] = useState<ReadonlySet<string>>(new Set());
  const [hasSearched, setHasSearched] = useState(false);
  const [isSearching, setIsSearching] = useState(false);
  const [showFilters, setShowFilters] = useState(false);
  const [results, setResults] = useState<readonly VocationalOpportunity[]>([]);

  const opportunities = contentCatalog.payload;
  const categories = useMemo(() => listVocationalCategories(opportunities), [opportunities]);
  const categoryPreviews = useMemo<readonly VocationalCategoryPreview[]>(
    () => categories.slice(0, VOCATIONAL_CATEGORY_PREVIEW_LIMIT).map((category) => ({
      name: category,
      iconKey: VOCATIONAL_CATEGORY_ICON_KEYS[category],
      color: VOCATIONAL_CATEGORY_STYLE_CLASSES[category],
    })),
    [categories],
  );
  const displayResults = useMemo(
    () => filterVocationalOpportunities(results, searchQuery, categoryFilter),
    [categoryFilter, results, searchQuery],
  );
  const stats = useMemo(
    () => calculateVocationalStats(displayResults, savedOpportunityIds.size),
    [displayResults, savedOpportunityIds.size],
  );

  const updateZipCode = (value: string) => {
    setZipCode(normalizeVocationalZipCode(value));
  };

  const updateCategoryFilter = (value: string) => {
    setCategoryFilter(toVocationalCategoryFilter(value, categories));
  };

  const searchByZipCode = () => {
    if (zipCode.length < 5 || isSearching) {
      return;
    }

    setIsSearching(true);
    if (searchTimeoutRef.current !== null) {
      window.clearTimeout(searchTimeoutRef.current);
    }

    searchTimeoutRef.current = window.setTimeout(() => {
      setResults(searchVocationalOpportunitiesByZip(opportunities, zipCode));
      setHasSearched(true);
      setIsSearching(false);
      searchTimeoutRef.current = null;
    }, VOCATIONAL_SEARCH_DELAY_MS);
  };

  useEffect(() => () => {
    if (searchTimeoutRef.current !== null) {
      window.clearTimeout(searchTimeoutRef.current);
    }
  }, []);

  const toggleFilters = () => {
    setShowFilters((current) => !current);
  };

  const toggleExpandedOpportunity = (id: string) => {
    setExpandedOpportunityId((current) => (current === id ? null : id));
  };

  const toggleSavedOpportunity = (id: string) => {
    setSavedOpportunityIds((current) => {
      const next = new Set(current);
      if (next.has(id)) {
        next.delete(id);
      } else {
        next.add(id);
      }
      return next;
    });
  };

  return {
    zipCode,
    searchQuery,
    categoryFilter,
    expandedOpportunityId,
    savedOpportunityIds,
    hasSearched,
    isSearching,
    showFilters,
    categories,
    categoryPreviews,
    displayResults,
    stats,
    isLoading: contentCatalog.isLoading,
    error: contentCatalog.error,
    updateZipCode,
    setSearchQuery,
    updateCategoryFilter,
    searchByZipCode,
    toggleFilters,
    toggleExpandedOpportunity,
    toggleSavedOpportunity,
  };
}
