import React, { useEffect, useRef, useState, useMemo, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { useParams } from 'react-router';
import { useRealtime } from './contexts/RealtimeContext';

const EditCellPortal = React.memo(({
  cell,
  table,
  EditCell,
  onSaveStart,
  onSaveEnd,
  onError,
  isEditable
}) => {
  const { formId, formType, sheetName, direction } = useParams();
  const tableKey = `${formId}_${formType}_${sheetName}_${direction}`;
  const ref = useRef(null);
  const [refTbody, setRefTbody] = useState(null);
  const [isSaving, setIsSaving] = useState(false);

  const { endEditing: contextEndEditing } = useRealtime();

  useEffect(() => {
    if (ref.current) {
      const tbodyRef = ref.current.offsetParent?.offsetParent?.offsetParent;
      if (tbodyRef && tbodyRef !== refTbody) {
        setRefTbody(tbodyRef);
      }
    }
  }, []);

  const handleChange = useCallback( (val) => {
    table.setEditingCell(null);
    try {
      if (table.options.meta?.updateCell) {
        const success = table.options.meta.updateCell(
          cell.row,
          cell.column,
          val
        );
        if (!success) {
          console.error('Failed to update cell via WebSocket');
          onError?.('Не удалось сохранить изменение');
        }
      }
    } catch (error) {
      console.error('Error updating cell:', error);
      onError?.(error.message);
    }
  }, [table, cell, onError]);

  const editCellProps = useMemo(() => ({
    refCell: ref,
    cell,
    value: cell.getValue(),
    disabled: !isEditable,
    onChange: handleChange,
    tableId: tableKey,
    table,
    cellId: `${cell.row.id}_${cell.column.id}`,
  }), [cell, isEditable, handleChange, tableKey, table]);

  const portalContent = useMemo(() => {
    if (!refTbody || isSaving) return null;
    return createPortal(
      <EditCell {...editCellProps} />,
      refTbody
    );
  }, [refTbody, isSaving, editCellProps, EditCell]);

  return (
    <>
      <div ref={ref} style={{ width: '100%', height: '100%' }} />
      {portalContent}   
    </>
  );
});


export const getTableColumns = ({
  Cell,
  EditCell,
  columnsConfig,
  onCellUpdateError,
  onCellNumberClick,
}) => {
  const columnColors = { ...columnsConfig.colors };
  const columns = structuredClone(columnsConfig.columns);

  const cellPropsCache = new WeakMap();
  const editPropsCache = new WeakMap();

  const getCachedCellProps = (row, column, table) => {
    const key = `${row.id}_${column.id}`;

    if (!cellPropsCache.has(row)) {
      cellPropsCache.set(row, {});
    }

    const rowCache = cellPropsCache.get(row);
    if (rowCache[key]) {
      const cached = rowCache[key];
      const currentGlobalFilter = table.getState().globalFilter;
      const currentColumnFilter = table.getState().columnFilters?.find(f => f.id === column.id)?.value;

      if (cached.globalFilter === currentGlobalFilter &&
        cached.columnFilter === currentColumnFilter) {
        return cached;
      }
    }

    const globalFilter = table.getState().globalFilter;
    const columnFilter = table.getState().columnFilters?.find(f => f.id === column.id)?.value;

    const props = {
      globalFilter,
      columnFilter,
      isEditable: row.original?.row_type === 'INPUT' || false,
      backgroundColor: columnColors[column.id]?.color_type?.[row.original?.row_type || row.row_type],
      isUpdating: table.options.meta?.updatingCells?.[`${row.id}_${column.id}`],
      _hash: `${globalFilter}_${columnFilter}_${row.id}_${column.id}`,
    };

    rowCache[key] = props;
    return props;
  };

  const getCachedEditProps = (row, column, table) => {
    const key = `${row.id}_${column.id}`;

    if (!editPropsCache.has(row)) {
      editPropsCache.set(row, {});
    }

    const rowCache = editPropsCache.get(row);
    if (rowCache[key]) {
      return rowCache[key];
    }

    const props = {
      isEditable: row.original?.row_type === 'INPUT' || false,
    };

    rowCache[key] = props;
    return props;
  };

  // Оптимизированная функция processColumns
  const processColumns = (columns) => {
    columns.forEach((col) => {
      col.Cell = ({ cell, table, column, row }) => {
        const props = getCachedCellProps(row, column, table);

        const cellProps = useMemo(() => ({
          row,
          column,
          cell,
          ...props,
        }), [row.id, column.id, cell.getValue(), props._hash]);

        return <Cell {...cellProps} />;
      };

      col.Edit = ({ cell, table, row, column }) => {
        const props = getCachedEditProps(row, column, table);

        const editComponent = useMemo(() => (
          <EditCellPortal
            cell={cell}
            table={table}
            EditCell={EditCell}
            onError={onCellUpdateError}
            isEditable={props.isEditable}
          />
        ), [cell, table, EditCell, onCellUpdateError, props.isEditable]);

        return editComponent;
      };

      if (col.columns?.length) {
        processColumns(col.columns);
      }
    });
  };

  processColumns(columns);

  const rowNumber = {
    accessorKey: 'sort_order',
    header: '#',
    size: 50,
    enableEditing: false,
    Cell: ({ cell, row }) => {
      const handleClick = useCallback(() => {
        onCellNumberClick(row.id);
      }, [row.id, onCellNumberClick]);

      return <button onClick={handleClick}>{cell.getValue() + '   '}</button>;
    },
  };

  return [rowNumber, ...columns];
};