import type { SortKey, SortedBy } from './useCustomSorter';
import { useCustomSorter } from './useCustomSorter';
import { useState, useEffect } from 'react';

const DEFAULT_PAGE_SIZE = 5;

export function useDataControl<T>(rawData: T[] | null | undefined) {
  const [pageSize, setPageSize] = useState<number>(DEFAULT_PAGE_SIZE);
  const [currentPage, setCurrentPage] = useState<number>(1);
  const [sortedBy, setSortedBy] = useState<SortedBy<T>>(null);
  const [searchQuery, setSearchQuery] = useState<string>('');
  const [searchKeys, setSearchKeys] = useState<(keyof T)[] | undefined>(undefined);
  const { defaultSorter, sortFunction, setSortFunction } = useCustomSorter<T>(sortedBy);

  const qNorm = stripDiacritics((searchQuery || '').trim());

  const hasSearch = qNorm.length > 0 && Array.isArray(searchKeys) && searchKeys.length > 0;

  const filtered = !hasSearch
    ? rawData
    : rawData?.filter((item) =>
        (searchKeys as (keyof T)[]).some((key) => {
          const v = item[key];

          if (typeof v === 'number') return v.toString().includes(qNorm);

          const normalized = stripDiacritics(toSearchable(v));
          return normalized.includes(qNorm);
        }),
      );

  const sorted = !sortedBy ? filtered : filtered && [...filtered].sort((a, b) => sortFunction(a, b, defaultSorter));

  const sortBy = (key?: Extract<keyof T, string> | null) => {
    if (!key) return;
    if (sortedBy?.startsWith(`${String(key)}-`)) {
      const direction = sortedBy?.endsWith('-asc') ? 'desc' : 'asc';
      return setSortedBy(`${key}-${direction}`);
    }
    return setSortedBy(`${key}-asc`);
  };

  const [sortKey, sortDirection] = (sortedBy || '').split('-') as [SortKey<T> | null, 'asc' | 'desc'] | [null, null];

  const effectivePageSize = pageSize ?? (sorted?.length || 1);
  const pageCount = Math.max(1, Math.ceil((sorted?.length || 1) / effectivePageSize));

  const currentPageClamped = Math.min(currentPage, pageCount);
  const start = (currentPageClamped - 1) * effectivePageSize;
  const end = start + effectivePageSize;
  const pageData = sorted?.slice(start, end);

  useEffect(() => {
    setCurrentPage(1);
  }, [qNorm, searchKeys, sortedBy]);

  const changePage = (p: number) => {
    const clamped = Math.min(Math.max(1, Math.floor(p)), pageCount);
    setCurrentPage(clamped);
  };
  return {
    rawData,
    data: pageData,
    currentPage: currentPageClamped,
    changePage,
    pageSize: effectivePageSize,
    setPageSize,
    resetPageSize: () => setPageSize(+DEFAULT_PAGE_SIZE),
    searchQuery,
    setSearchQuery,
    searchKeys,
    setSearchKeys,
    setCustomSort: setSortFunction,
    pageCount,
    sortedBy,
    setSortedBy,
    sortKey,
    sortDirection,
    sortBy,
  };
}

export type UseDataControlReturn<T> = ReturnType<typeof useDataControl<T>>;
export type { SortKey, SortedBy };

const stripDiacritics = (s: string) =>
  s
    .normalize('NFD')
    .replace(/\p{Diacritic}/gu, '')
    .toLowerCase();

const toSearchable = (v: unknown) => {
  if (v == null) return '';
  if (v instanceof Date) return v.toISOString();
  return String(v);
};
