import React, { useState, useMemo, useRef, useEffect, useCallback, useTransition } from 'react';
import { createPortal } from 'react-dom';
import {
  useMaterialReactTable,
  MaterialReactTable,
} from 'material-react-table';

import useRealtimeData from './hooks/useRealtimeData';
import { getTableColumns } from './tableColumns';
import { Cell, EditCell } from './index';
import { TableHead } from './TableHead/TableHead';
import SettingsPanel from './SettingPanel/SettingPanel';
import { ColumnSelectionOverlay } from './ColumnSelectionOverlay/ColumnSelectionOverlay';

import { useColumnSettings } from './hooks/useColumnSettings';
import { useTableScale } from './hooks/useTableScale';
import { useHeaderPortal } from './hooks/useHeaderPortal';
import {
  BASE_TABLE_CONFIG,
  getTableBodyCellProps,
  getTablePaperStyles,
  TABLE_ROW_HEIGHT,
} from './constants/tableConfig';
import { useRealtime } from './contexts/RealtimeContext';
import { toast } from 'react-toastify';
import { CircularProgress } from '@mui/material';
import { additionExpenseRowTable, additionVspRowTable } from './constants/addingRowConfig';
import { SelectVspModal } from './Modals/SelectVspModal';
import { SelectExpenseItemModal } from './Modals/SelectExpenseItemModal';
import { getRowId } from './utils/rowUtils';
import { FORM_TYPE_OPTIONS } from '../../constants/constants';
import { debounce } from '@mui/material';
import { CreateProgramModal } from './Modals/CreateProgramProjectModal';

const RealtimeTable = ({ formType, formId, sheetName, direction, year }) => {
  const { data, setData, isLoading: isTableLoading, editingCells: dataEditingCells } = useRealtimeData(formId, sheetName, direction, formType, year);
  const [globalFilter, setGlobalFilter] = useState('');
  const [showColumnFilters, setShowColumnFilters] = useState(false);
  const [selectedColumnId, setSelectedColumnId] = useState();
  const [rowSelection, setRowSelection] = useState({});
  const [isLoadingData, setIsLoadingData] = useState(false);
  const [isPending, startTransition] = useTransition();
  const [editingCell, setEditingCell] = useState(null);

  const [isOpenModalSelectVsp, setIsOpenModalSelectVsp] = useState(false);
  const [isOpenModalSelectExpenseItem, setIsOpenModalSelectExpenseItem] = useState(false);
  const [isOpenModalCreateProgram, setIsOpenModalCreateProgram] = useState(false);
  const [isOpenModalCreateProject, setIsOpenModalCreateProject] = useState(false);
  const [isProgramCreate, setIsProgramCreate] = useState(false)

  const isVspAdditionRow = useMemo(() => {
    if (!formType || !sheetName) return false;
    if (!additionVspRowTable[formType]) return false;
    return additionVspRowTable[formType].includes(sheetName);
  }, [formType, sheetName]);

  const isAdditionExpenseItem = useMemo(() => {
    if (!formType || !sheetName) return false;
    if (!additionExpenseRowTable[formType]) return false;
    return additionExpenseRowTable[formType].includes(sheetName);
  }, [formType, sheetName]);

  const handleGlobalFilterChange = useCallback(
    debounce((value) => {
      startTransition(() => {
        setGlobalFilter(value);
      });
    }, 300),
    []
  );

  const {
    isConnected,
    isAuthenticated,
    subscribeToErrors,
    subscribeToAuthSuccess,
    error: wsError,
    updateCell: contextUpdateCell,
    addRow: contextAddRow,
    deleteRow: contextDeleteRow,
    startEditing: contextStartEditing,
    addProgram: contextAddProgram,
    addProject: contextAddProject,
  } = useRealtime();

  const {
    columnSizing,
    columnPinning,
    columnVisibility,
    setColumnSizing,
    setColumnPinning,
    handlePinColumn,
    handleUnpinColumn,
    handleSetColumnWidth,
    handleToggleColumnVisibility,
  } = useColumnSettings(`${formId}_${formType}_${sheetName}_${direction}`);

  const { headerPortalRef, containerRef } = useHeaderPortal();
  const rowVirtualizerRef = useRef(null);

  const { sizeMult, setSizeMult, tableScaleStyle, tableWrapperStyle } =
    useTableScale();

  useEffect(() => {
    rowVirtualizerRef.current?.measure?.();
  }, [sizeMult]);

  const [columnsConfig, setColumnsConfig] = useState(null);

  const configCache = useRef(new Map());

  useEffect(() => {
    if (!formType || !sheetName) return;
    const cacheKey = `${formType}_${sheetName}`;

    if (configCache.current.has(cacheKey)) {
      setColumnsConfig(configCache.current.get(cacheKey));
      return;
    }

    const loadConfig = async () => {
      try {
        const { config } = await import(`./constants/${formType}/${sheetName}.js`);
        configCache.current.set(cacheKey, config.config);
        setColumnsConfig(config.config);
      } catch (error) {
        console.error(`Failed to load config for ${formType}/${sheetName}:`, error);
        setColumnsConfig({ columns: [], colors: {} });
      }
    };

    loadConfig();
  }, [formType, sheetName]);

  const handleUpdateCell = useCallback(async (row, column, value) => {
    return await contextUpdateCell(row, column, value);
  }, [contextUpdateCell]);

  const handleClickRowCell = useCallback((rowId) => {
    setRowSelection((prev) => ({
      [rowId]: !prev[rowId],
    }));
  }, [])

  const handleColumnSelect = useCallback((columnId) => {
    setSelectedColumnId((prev) => {
      const next = prev === columnId ? undefined : columnId;
      return next;
    });
  }, []);

  useEffect(() => {
    if (!selectedColumnId) return;

    const handleDocumentClick = (e) => {
      if (e.target.closest('[data-col-select-id]')) return;
      if (e.target.closest('[data-pin-panel]')) return;

      setSelectedColumnId(undefined);
    };

    document.addEventListener('mousedown', handleDocumentClick);
    return () => document.removeEventListener('mousedown', handleDocumentClick);
  }, [selectedColumnId]);

  const handleCellUpdateError = useCallback((rowId, columnId, error) => {
    console.error(`Error updating cell ${rowId}_${columnId}:`, error);
    toast.error('Ошибка обновления ячейки');
  }, []);

  const columns = useMemo(() => {
    if (!columnsConfig || !columnsConfig.columns) return [];
    try {
      return getTableColumns({
        Cell,
        EditCell,
        columnsConfig,
        onCellUpdate: handleUpdateCell,
        onCellNumberClick: handleClickRowCell,
        onCellUpdateError: handleCellUpdateError,
      });
    } catch (error) {
      console.error('Error creating columns:', error);
      return [];
    }
  }, [columnsConfig]);

  const selectedColumnIdRef = useRef(selectedColumnId);

  useEffect(() => {
    selectedColumnIdRef.current = selectedColumnId;
  }, [selectedColumnId]);

  const tableMeta = useMemo(() => ({
    updateCell: handleUpdateCell,
    getSelectedColumnId: () => selectedColumnIdRef.current,
  }), [handleUpdateCell]);

  const ROW_VIRTUALIZER_OPTIONS = {
    overscan: 5,
    scrollPaddingStart: 0,
    scrollPaddingEnd: 0,
    estimateSize: () => TABLE_ROW_HEIGHT,
    measureElement: (el) => el?.offsetHeight || TABLE_ROW_HEIGHT,
  };

  const createTableConfig = ({
    columns,
    data,
    columnSizing,
    columnPinning,
    columnVisibility,
    globalFilter,
    showColumnFilters,
    rowSelection,
    containerRef,
    tableMeta,
    setColumnSizing,
    setColumnPinning,
    editingCell,
    contextStartEditing,
  }) => ({
    ...BASE_TABLE_CONFIG,
    columns,
    data,
    enableRowVirtualization: true,
    enableColumnVirtualization: true,
    rowVirtualizerInstanceRef: rowVirtualizerRef,
    rowVirtualizerOptions: ROW_VIRTUALIZER_OPTIONS,
    onEditingCellChange: (cell) => {
      if (cell && !editingCell) {
        contextStartEditing?.(cell.row, cell.column);
      }
    },
    columnVirtualizerOptions: ({ table }) => ({
      overscan: 10,
      measureElement: (el) => {
        if (!el) return 150;
        const index = Number(el?.getAttribute?.('data-index'));
        const isPinned = Boolean(el?.getAttribute?.('data-pinned'));
        if (isPinned) {
          const colId = table.getState().columnPinning.left[index];
          const column = table.getColumn(colId);
          return column?.getSize() ?? 150;
        }
        const allCols = [...table.getLeftVisibleLeafColumns(), ...table.getCenterVisibleLeafColumns()]
        return allCols[index]?.getSize() ?? 150;
      },
    }),
    enableRowSelection: true,
    onRowSelectionChange: setRowSelection,
    onColumnSizingChange: setColumnSizing,
    onColumnPinningChange: setColumnPinning,
    onGlobalFilterChange: handleGlobalFilterChange,
    state: {
      columnSizing,
      columnPinning,
      columnVisibility,
      globalFilter,
      showColumnFilters,
      rowSelection,
      editingCell,
    },
    initialState: {
      expanded: true,
    },
    meta: tableMeta,
    muiTableHeadCellProps: {
      sx: { boxSizing: 'border-box' },
    },
    muiTableBodyCellProps: getTableBodyCellProps,
    muiTableHeadProps: {
      sx: {
        display: 'table-header-group',
        height: '1px',
        minHeight: '1px',
        maxHeight: '1px',
        visibility: 'hidden',
        '& svg': {
          height: '1px',
          minHeight: '1px',
          maxHeight: '1px',
          visibility: 'hidden',
        }
      },
    },
    muiTablePaperProps: getTablePaperStyles(),
    muiTableContainerProps: {
      ref: containerRef,
      sx: {
        position: 'relative',
        contain: 'layout',
        minHeight: '100%',
        '& .MuiTable-root': { position: 'relative' },
      },
    },
    muiTableHeadCellFilterTextFieldProps: {
      placeholder: 'Поиск...',
      size: 'small',
    },
  });

  // Конфигурация таблицы
  const tableConfig = useMemo(() => createTableConfig({
    columns,
    data,
    columnSizing,
    columnPinning,
    columnVisibility,
    globalFilter,
    showColumnFilters,
    rowSelection,
    containerRef,
    tableMeta,
    setColumnSizing,
    setColumnPinning,
    editingCell,
    contextStartEditing,
  }), [
    columns,
    data,
    columnSizing,
    columnPinning,
    columnVisibility,
    globalFilter,
    showColumnFilters,
    rowSelection,
    containerRef,
    tableMeta,
    setColumnSizing,
    setColumnPinning,
    editingCell,
  ]);

  const table = useMaterialReactTable(tableConfig);

  useEffect(() => {
    if (!dataEditingCells?.line_id) {
      setEditingCell(null);
      return;
    }
    if (editingCell) return;

    // Отложить поиск до следующего тика
    requestAnimationFrame(() => {
      try {
        const row = table.getRow(dataEditingCells.line_id);
        const cell = row?.getVisibleCells().find(
          c => c.column.id === dataEditingCells.column
        );
        if (cell) setEditingCell(cell);
      } catch (error) {
        console.error(error);
      }
    });
  }, [dataEditingCells, editingCell, table]);

  const [isFirstLoad, setIsFirstLoad] = useState(true);

  useEffect(() => {
    if (isFirstLoad && table && data && columns.length !== 0) {
      setIsFirstLoad(false);
      setIsLoadingData(true);
    }
  }, [data, columns, table, isFirstLoad]);

  const handleAddRow = useCallback(() => {
    const allRows = table.getRowModel().rows;

    const selectedRows = allRows.filter(row => rowSelection[row.id]);
    if (selectedRows.length === 0) {
      toast.error('Выделите строку для вставки');
      return;
    }
    const row = selectedRows[0];
    const expense_item_id = row.original.data.header.expense_item_id;
    contextAddRow({ expense_item_id: expense_item_id })
  }, [rowSelection, table])

  const handleAddVspRow = useCallback((vsp_id) => {
    contextAddRow({ vsp_id: vsp_id });
  }, []);

  const handleAddExpenseItemRow = useCallback((expense_item) => {
    const allRows = table.getRowModel().rows;
    const selectedRows = allRows.filter(row => rowSelection[row.id]);
    const row = selectedRows[0];
    contextAddRow({ expense_item_id: expense_item.id, project_id: row.original.data.header.project_id });
  }, [rowSelection]);

  const handleAddProgramRow = useCallback((name) => {
    contextAddProgram({ name: name });
  }, []);

  const handleAddProjectRow = useCallback((name) => {
    const allRows = table.getRowModel().rows;
    const selectedRows = allRows.filter(row => rowSelection[row.id]);
    const row = selectedRows[0];
    contextAddProject({ name: name, program_id: row.original.data.header.program_id });
  }, [rowSelection]);

  const handleOpenModalSelectVsp = useCallback(() => {
    setIsOpenModalSelectVsp(true);
  }, [])

  const handleOpenModalSelectExpenseItem = useCallback(() => {
    const allRows = table.getRowModel().rows;

    const selectedRows = allRows.filter(row => rowSelection[row.id]);
    if (selectedRows.length === 0) {
      toast.error('Выделите строку для вставки');
      return;
    }
    const row = selectedRows[0];
    if (row.original.row_type !== 'ITEM') {
      toast.error('Выделите строку проекта');
      return;
    }
    setIsOpenModalSelectExpenseItem(true);
  }, [rowSelection])

  const handleDeleteRow = useCallback(() => {
    const allRows = table.getRowModel().rows;

    const selectedRows = allRows.filter(row => rowSelection[row.id]);
    if (selectedRows.length === 0) {
      toast.error('Выделите строку для удаления');
      return;
    }
    const row = selectedRows[0];
    const rowId = getRowId(row);
    contextDeleteRow(rowId);
    setRowSelection({});
  }, [rowSelection, table])

  const addRow = useCallback(() => {

    if (isVspAdditionRow) {
      return handleOpenModalSelectVsp();
    }
    if (isAdditionExpenseItem) {
      return handleOpenModalSelectExpenseItem();
    }
    return handleAddRow();
  }, [isVspAdditionRow, isAdditionExpenseItem, handleOpenModalSelectVsp, handleAddRow]);

  const addProgram = useCallback(() => {
    setIsProgramCreate(true);
    setIsOpenModalCreateProgram(true);
  }, [setIsOpenModalCreateProgram])

  const addProject = useCallback(() => {
    setIsProgramCreate(false);
    const allRows = table.getRowModel().rows;

    const selectedRows = allRows.filter(row => rowSelection[row.id]);
    if (selectedRows.length === 0) {
      toast.error('Выделите строку для вставки');
      return;
    }
    const row = selectedRows[0];
    if (row.original.row_type !== 'GROUP') {
      toast.error('Выделите строку программы');
      return;
    }
    setIsOpenModalCreateProgram(true);
  }, [setIsOpenModalCreateProgram, rowSelection])

  useEffect(() => {
    return () => {
      setData([]);
      setRowSelection({});
      setEditingCell(null);
      if (rowVirtualizerRef.current) {
        rowVirtualizerRef.current = null;
      }
    };
  }, []);

  return (
    <>
      <SettingsPanel
        selectedColumnId={selectedColumnId}
        columnPinning={columnPinning}
        table={table}
        columns={columns}
        onPinColumn={handlePinColumn}
        onUnpinColumn={handleUnpinColumn}
        onToggleColumnVisibility={handleToggleColumnVisibility}
        columnVisibility={columnVisibility}
        onChangeSizeMult={setSizeMult}
        onGlobalFilterChange={handleGlobalFilterChange}
        sizeMult={sizeMult}
        onChangeShowColumnFilters={setShowColumnFilters}
        onAddRow={addRow}
        onAddProgram={addProgram}
        onAddProject={addProject}
        onDeleteRow={handleDeleteRow}
        isLoadingData={isLoadingData}
        formId={formId}
        sheetName={sheetName}
        direction={direction}
        year={year}
        isProject={formType == 'PROJECT'}
        formType={formType}
      />

      <div style={tableWrapperStyle}>
        <div style={tableScaleStyle}>
          <div
            style={{
              position: 'relative',
              width: '100%',
              flex: 1,
              minHeight: 0,
              height: '100%',
            }}
          >
            <MaterialReactTable table={table} />

            <ColumnSelectionOverlay
              selectedColumnId={selectedColumnId}
              containerRef={containerRef}
              scale={sizeMult}
              columnSizing={columnSizing}
              columnPinning={columnPinning}
              showColumnFilters={showColumnFilters}
            />

            {isTableLoading && (
              <div
                style={{
                  position: 'absolute',
                  inset: 0,
                  display: 'flex',
                  alignItems: 'center',
                  justifyContent: 'center',
                  background: 'rgba(255, 255, 255, 0.6)',
                  zIndex: 2,
                }}
              >
                <CircularProgress />
              </div>
            )}

            {headerPortalRef.current &&
              createPortal(
                <TableHead
                  table={table}
                  style={{ zIndex: (theme) => theme.zIndex.modal - 1 }}
                  selectedColumnId={selectedColumnId}
                  onColumnSelect={handleColumnSelect}
                  onChangeWidth={handleSetColumnWidth}
                  isLoadingData={isLoadingData}
                />,
                headerPortalRef.current,
              )}
          </div>
        </div>
      </div>
      <SelectVspModal
        isOpen={isOpenModalSelectVsp}
        onClose={() => setIsOpenModalSelectVsp(false)}
        formId={formId}
        onSelect={handleAddVspRow}
        title="Выбор ВСП"
      />
      <SelectExpenseItemModal
        isOpen={isOpenModalSelectExpenseItem}
        onClose={() => setIsOpenModalSelectExpenseItem(false)}
        formId={formId}
        onSelect={handleAddExpenseItemRow}
        title="Добавление строки"
        sheet={sheetName}
      />
      <CreateProgramModal
        isOpen={isOpenModalCreateProgram}
        onClose={() => setIsOpenModalCreateProgram(false)}
        title={isProgramCreate ? "Создание программы" : "Создание проекта"}
        onCreate={isProgramCreate ? handleAddProgramRow : handleAddProjectRow}
      />
    </>
  );
};

export default React.memo(RealtimeTable);