import { useState, useEffect, useCallback, useMemo } from 'react';
import { getComparator, useTable } from '@/shared/components/table';
import { TableColumn } from '@/shared/types/common';
import { enqueueSnackbar } from 'notistack';

export interface TableConfig<T> {
  type?:string;
  initialData: T[];
  defaultTableHead: TableColumn[];
}
const isValidDate = (dateString: string): boolean => {
  const date = new Date(dateString);
  return !isNaN(date.getTime());
};

export function useTableManager<T extends { id: string }>(config: TableConfig<T>) {
  const table = useTable({defaultOrderBy : config.defaultTableHead[0].id});
  const [tableData, setTableData] = useState<T[]>([]);
  const [filters, setFilters] = useState<Record<string, {value: string, condition: string}>>({});
  const [tableHead, setTableHead] = useState(config.defaultTableHead);

  useEffect(() => {
    setTableData(config.initialData);
  }, [config.initialData]);

  const handleFilterChange = useCallback((key: string, value: string, condition: string) => {
    setFilters(prev => ({
      ...prev,
      [key]: { value, condition }
    }));
  }, []);

  const handleResetFilters = useCallback(() => setFilters({}), []);
  
  const handleResetColumns = useCallback(() => setTableHead(config.defaultTableHead), [config.defaultTableHead]);
  
  const handleColumnsChange = useCallback((columns: { id: string; label: string }[]) => {
    const newTableHead = columns.map(col => ({
      ...config.defaultTableHead.find(defaultCol => defaultCol.id === col.id)!,
      label: col.label,
    }));
    if (config.type === 'feuille de route soumise') {
      newTableHead.push({ id: 'contacter', label: 'Contacter' });
    }  
     newTableHead.push({ id: '', label: 'Action' });

    setTableHead(newTableHead);
  }, [config.defaultTableHead]);

  const applyFilters = useCallback((data: T[]) => {
    const comparator: (a: any, b: any) => number = getComparator(table.order, table.orderBy);
    const stabilizedThis = data.map((el, index) => [el, index] as const);
  
    stabilizedThis.sort((a, b) => {
      const order = comparator(a[0], b[0]);
      if (order !== 0) return order;
      return a[1] - b[1];
    });
  
    data = stabilizedThis.map((el) => el[0]);
    if (!filters || Object.keys(filters).length === 0) return data;
  
    return data.filter((item) =>
      Object.entries(filters).every(([key, { value, condition }]) => {
        if (value === null || value === '') return true;
        const itemValue = item[key as keyof T];
  
        if (typeof itemValue === 'string' && !isValidDate(value)) {
          const stringValue = itemValue.toLowerCase();
          const filterValue = value.toString().toLowerCase();
          switch (condition) {
            case 'contains':
              return stringValue.includes(filterValue);
            case 'equals':
              return stringValue === filterValue;
            case 'startsWith':
              return stringValue.startsWith(filterValue);
            case 'endsWith':
              return stringValue.endsWith(filterValue);
            default:
              return stringValue.includes(filterValue);
          }
        } else if (typeof itemValue === 'string' && isValidDate(value)) {
          const itemDate = new Date(itemValue);
          const filterDate = new Date(value);
          if (isNaN(itemDate.getTime()) || isNaN(filterDate.getTime())) return false;
  
          switch (condition) {
            case '<':
              return itemDate < filterDate;
            case '>':
              return itemDate > filterDate;
            case '=':
              return itemDate.getTime() === filterDate.getTime();
            default:
              return false;
          }
        } else if (typeof itemValue === 'boolean') {
          return itemValue === (value === 'true');
        }
        else if (typeof itemValue === 'number') {
          const numericValue = Number(value);
          if (isNaN(numericValue)) return false;
          return itemValue === numericValue;
        }
  
        return true;
      })
    );
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [table.order, table.orderBy, filters, config]);

  const filteredData = useMemo(() => applyFilters(tableData), [applyFilters, tableData]);
  const notFound = !filteredData.length;

  const handleSave = useCallback((updatedItem: T) => {
    let actionType;
    setTableData(prevData => {
      const index = prevData.findIndex(item => item.id === updatedItem.id);
      actionType = index !== -1 ? 'modifié' : 'créé';
      if (index !== -1) {
        const newData = [...prevData];
        newData[index] = updatedItem;
        return newData;
      } else {
        return [...prevData, updatedItem];
      }
    });
    const message = config.type 
      ? `${config.type} ${actionType} avec succès`
      : `Élément ${actionType} avec succès`;
      
    enqueueSnackbar(message, { variant: 'success' });
  }, [config.type]);

  const handleDelete = useCallback((id: string) => {
    setTableData(prevData => prevData.filter(item => item.id !== id));
  }, []);
  
  const handleStatusChange = useCallback((row: T, newStatus: string, field: keyof T) => {
    const updatedItem = {
      ...row,
      [field]: newStatus,
    };
    handleSave(updatedItem);
  }, [handleSave]);
 
  const dataToExport = useMemo(() => (
    table.selected.length > 0
      ? filteredData.filter(item => table.selected.includes(item.id))
      : []
  ), [filteredData, table.selected]);

  return {
    table,
    tableData,
    filteredData,
    filters,
    tableHead,
    notFound,
    handleFilterChange,
    handleResetFilters,
    handleResetColumns,
    handleColumnsChange,
    handleSave,
    handleDelete,
    handleStatusChange,
    dataToExport
  };
}

