import { useFileData, useLatestFileForTemplate } from '@/hook/useFileQueries'
import { useMultiSheetEngine } from '@/hook/useMultiSheetEngine'
import { useSheetAutoSave } from '@/hook/useSheetAutoSave'
import { produce } from 'immer'
import React, {
  FC,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react'

// Импорты из новых модулей
import { FormulaBar, Spreadsheet } from './components'
import { useDraggableDivider } from './hooks/useDraggableDivider'
import {
  CachedCellData,
  CellSelection,
  COL_COUNT,
  DualSpreadsheetProps,
  HighlightedCell,
  ROW_COUNT,
  SHEET_NAMES,
  SHEET_TYPES,
  SheetType,
} from './types'
import {
  convertReferencesToHighlights,
  createCellAddress,
  createQualifiedCellReference,
  createSelectionFromRange,
  extractCellReferences,
  getAllCellsInSelections,
  getColumnLabel,
} from './utils'

const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
  templateData = {},
  mergedCells = [],
  templateId,
  onEngineReady,
  excelFileName,
  isExcelLoading = false,
  onExcelFileChange,
}) => {
  // Мемоизируем конфигурацию листов
  const sheetsConfig = useMemo(
    () => [
      { name: SHEET_NAMES.report, rows: ROW_COUNT, cols: COL_COUNT },
      { name: SHEET_NAMES.calculations, rows: ROW_COUNT, cols: COL_COUNT },
    ],
    []
  )

  const { revision, updateRevision, setTemplateData, ...multiSheetEngine } =
    useMultiSheetEngine({
      sheets: sheetsConfig,
      initialData: templateData || {},
    })

  const [activeSheet, setActiveSheet] = useState<SheetType>('report')
  const [selectedCell, setSelectedCell] = useState<{
    row: number
    col: number
  } | null>(null)

  // Флаг, что пользователь изменил хотя бы одну ячейку
  const [userEdited, setUserEdited] = useState(false)

  // Состояние для множественного выделения
  const [multiSelection, setMultiSelection] = useState<CellSelection[]>([])
  const [isDragging, setIsDragging] = useState(false)
  const [dragStart, setDragStart] = useState<{
    row: number
    col: number
  } | null>(null)
  const [isEditing, setIsEditing] = useState(false)
  const [editingValue, setEditingValue] = useState<string>('') // Локальное значение во время редактирования
  // Источник ввода: 'cell' (редактирование внутри ячейки) или 'formula'
  const [editingSource, setEditingSource] = useState<'cell' | 'formula'>('cell')
  const [isInitialized, setIsInitialized] = useState(false)
  const [baseFileData, setBaseFileData] = useState<
    Record<string, Record<string, any>>
  >({}) // Базовые данные файла
  const [highlightedCells, setHighlightedCells] = useState<HighlightedCell[]>(
    []
  )

  // Состояние для копирования/вставки
  const [copiedCells, setCopiedCells] = useState<{
    data: { row: number; col: number; value: string; rawValue: string }[]
    sourceSheet: SheetType
    isCut: boolean
  } | null>(null)

  // React Query хуки для оптимизации API запросов
  const { data: latestFile, isLoading: isLoadingLatestFile } =
    useLatestFileForTemplate(templateId)
  const { data: fileData, isLoading: isLoadingFileData } = useFileData(
    latestFile?.id
  )

  // Мемоизируем начальное состояние ширин колонок
  const initialColumnWidths = useMemo(
    () => ({
      report: Array(COL_COUNT).fill(96),
      calculations: Array(COL_COUNT).fill(96),
    }),
    []
  )

  const [columnWidths, setColumnWidths] =
    useState<Record<SheetType, number[]>>(initialColumnWidths)

  const gridRefs = useRef<Record<SheetType, any>>({
    report: null,
    calculations: null,
  })
  const containerRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
    report: null,
    calculations: null,
  })
  const headerRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
    report: null,
    calculations: null,
  })
  const rowHeaderRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
    report: null,
    calculations: null,
  })

  const activeCellInputRef = useRef<HTMLInputElement | null>(null)
  const formulaBarRef = useRef<HTMLInputElement | null>(null)
  const initialTemplateValues = useRef<Record<string, string>>({})

  const cellDataCache = useRef<Record<string, Record<string, CachedCellData>>>(
    {}
  )
  const lastRevision = useRef<number>(-1)

  // Мемоизируем обработчик обновления начальных значений
  const updateInitialValues = useCallback(() => {
    // Обновляем начальные значения только если есть данные
    const hasBaseFileData = Object.keys(baseFileData).length > 0
    const hasTemplateData = Object.keys(templateData).length > 0

    if (hasBaseFileData) {
      Object.entries(baseFileData).forEach(([sheetName, sheetData]) => {
        Object.entries(sheetData).forEach(([cellAddress, value]) => {
          initialTemplateValues.current[cellAddress] = String(value || '')
        })
      })
    } else if (hasTemplateData) {
      Object.entries(templateData).forEach(([sheetName, sheetData]) => {
        Object.entries(sheetData).forEach(([cellAddress, value]) => {
          initialTemplateValues.current[cellAddress] = String(value || '')
        })
      })
    }
  }, [baseFileData, templateData])

  useEffect(() => {
    updateInitialValues()
  }, [updateInitialValues])

  // Мемоизируем обработчик скролла к выбранной ячейке
  const scrollToSelectedCell = useCallback(() => {
    if (selectedCell && activeSheet) {
      const grid = gridRefs.current[activeSheet]
      grid?.scrollToItem({
        rowIndex: selectedCell.row,
        columnIndex: selectedCell.col,
        align: 'auto',
      })
    }
  }, [selectedCell, activeSheet])

  useEffect(() => {
    scrollToSelectedCell()
  }, [scrollToSelectedCell])

  const getCachedCellData = useCallback(
    (sheetType: SheetType): Record<string, CachedCellData> => {
      const cacheKey = `${sheetType}-${revision}-${columnWidths[sheetType].join('-')}`

      if (cellDataCache.current[cacheKey]) {
        return cellDataCache.current[cacheKey]
      }

      const sheetName = SHEET_NAMES[sheetType]
      const cachedData: Record<string, CachedCellData> = {}

      const allCellValues: Record<string, string> = {}
      for (let row = 0; row < ROW_COUNT; row++) {
        for (let col = 0; col < COL_COUNT; col++) {
          const cellKey = `${row}-${col}`
          const displayValue = String(
            multiSheetEngine.getCellValue(sheetName, row, col) || ''
          )
          allCellValues[cellKey] = displayValue.trim()
        }
      }

      // 1. Находим ближайшую занятую колонку справа для каждой ячейки строки
      const nextContentInRow: Record<number, number[]> = {}
      for (let row = 0; row < ROW_COUNT; row++) {
        nextContentInRow[row] = Array(COL_COUNT).fill(COL_COUNT)
        let next = COL_COUNT
        for (let col = COL_COUNT - 1; col >= 0; col--) {
          const cellKey = `${row}-${col}`
          nextContentInRow[row][col] = next // сохранить для использования ниже
          if (allCellValues[cellKey]) {
            next = col // текущая колонка занята → "новый" предел
          }
        }
      }

      // 2. Заполняем cache
      for (let row = 0; row < ROW_COUNT; row++) {
        for (let col = 0; col < COL_COUNT; col++) {
          const cellKey = `${row}-${col}`
          const rawValue = multiSheetEngine.getCellRawValue(sheetName, row, col)
          const displayValue = allCellValues[cellKey]
          const nextCol = nextContentInRow[row][col]

          // ширина от текущей колонки до nextCol-1 включительно
          const availablePx = columnWidths[sheetType]
            .slice(col, nextCol)
            .reduce((sum, w) => sum + w, 0)

          const cellName = getColumnLabel(col) + (row + 1)
          const baseFileValue = initialTemplateValues.current[cellName] ?? '' // Базовое значение из файла

          // Нормализуем значения для сравнения
          const normalizeValue = (value: any): string => {
            if (value === null || value === undefined) return ''
            const str = String(value).trim()
            // Считаем "0" и пустую строку эквивалентными
            if (str === '0' || str === '') return ''
            return str
          }

          const normalizedBaseFile = normalizeValue(baseFileValue)
          const normalizedRaw = normalizeValue(rawValue)

          const isModified =
            sheetType === 'report' && normalizedRaw !== normalizedBaseFile

          cachedData[cellKey] = {
            displayValue,
            rawValue,
            isModified,
            nextContentCol: nextCol,
            availablePx,
          }
        }
      }

      if (lastRevision.current !== revision) {
        Object.keys(cellDataCache.current).forEach(key => {
          if (!key.endsWith(`-${revision}`)) {
            delete cellDataCache.current[key]
          }
        })
        lastRevision.current = revision
      }

      cellDataCache.current[cacheKey] = cachedData
      return cachedData
    },
    [revision, multiSheetEngine, initialTemplateValues, columnWidths]
  )

  // Функция для обновления подсветки ячеек при вводе формулы
  const updateCellHighlights = useCallback(
    (formula: string) => {
      if (!formula.startsWith('=')) {
        setHighlightedCells([])
        return
      }

      try {
        // Извлекаем ссылки на ячейки из формулы
        const references = extractCellReferences(formula)

        // Конвертируем ссылки в подсвеченные ячейки
        const highlights = convertReferencesToHighlights(
          references,
          activeSheet
        )

        setHighlightedCells(highlights)
      } catch (error) {
        console.error('Ошибка при обновлении подсветки ячеек:', error)
        setHighlightedCells([])
      }
    },
    [activeSheet]
  )

  const formulaBarValue = useMemo(() => {
    if (isEditing) {
      return editingValue
    }
    if (selectedCell) {
      const sheetName = SHEET_NAMES[activeSheet]
      return multiSheetEngine.getCellRawValue(
        sheetName,
        selectedCell.row,
        selectedCell.col
      )
    }
    return ''
  }, [
    isEditing,
    editingValue,
    selectedCell,
    activeSheet,
    multiSheetEngine,
    revision,
  ])

  useEffect(() => {
    if (isEditing && activeCellInputRef.current) {
      const input = activeCellInputRef.current
      input.focus()
      const length = input.value.length
      input.setSelectionRange(length, length)
    }
  }, [isEditing])

  // Синхронизация между formula bar и ячейкой при редактировании
  // Теперь полагаемся на controlled компонент через formulaBarValue

  // Обновление подсветки ячеек при вводе формулы
  useEffect(() => {
    if (isEditing) {
      updateCellHighlights(editingValue)
    } else {
      // Очищаем подсветку когда не редактируем
      setHighlightedCells([])
    }
  }, [isEditing, editingValue, updateCellHighlights])

  // Сбрасываем скопированные ячейки при смене активного листа
  useEffect(() => {
    if (copiedCells) {
      setCopiedCells(null)
    }
  }, [activeSheet])

  // Автоматический сброс скопированных ячеек через 30 секунд
  useEffect(() => {
    if (!copiedCells) return

    const timeout = setTimeout(() => {
      setCopiedCells(null)
    }, 30000) // 30 секунд

    return () => clearTimeout(timeout)
  }, [copiedCells])

  const startEditing = useCallback(() => {
    if (!selectedCell) return
    // Сбрасываем множественное выделение при начале редактирования
    setMultiSelection([])
    const sheetName = SHEET_NAMES[activeSheet]
    const rawValue = multiSheetEngine.getCellRawValue(
      sheetName,
      selectedCell.row,
      selectedCell.col
    )
    setIsEditing(true)
    setEditingValue(rawValue)
  }, [activeSheet, selectedCell, multiSheetEngine])

  const stopEditing = useCallback(
    (save: boolean) => {
      if (save && selectedCell) {
        const sheetName = SHEET_NAMES[activeSheet]

        multiSheetEngine.setCellValueWithoutRecalc(
          sheetName,
          selectedCell.row,
          selectedCell.col,
          editingValue
        )
        updateRevision()
        multiSheetEngine.debouncedRecalc()
      }
      setIsEditing(false)
      setEditingValue('')
      setEditingSource('cell')
      containerRefs.current[activeSheet]?.focus({ preventScroll: true })
    },
    [activeSheet, selectedCell, editingValue, multiSheetEngine, updateRevision]
  )

  const handleCellChange = useCallback(
    (newValue: string) => {
      if (isEditing) {
        setEditingValue(newValue)
        if (!userEdited) setUserEdited(true)
      }
    },
    [isEditing, userEdited]
  )

  const handleClearCell = useCallback(() => {
    if (!selectedCell) return
    const sheetName = SHEET_NAMES[activeSheet]

    multiSheetEngine.setCellValueWithoutRecalc(
      sheetName,
      selectedCell.row,
      selectedCell.col,
      ''
    )
    setUserEdited(true)
    updateRevision()
    multiSheetEngine.debouncedRecalc()
    setMultiSelection([])
  }, [activeSheet, selectedCell, multiSheetEngine, updateRevision])

  const moveSelection = useCallback(
    (deltaRow: number, deltaCol: number) => {
      if (!selectedCell) {
        setSelectedCell({ row: 0, col: 0 })
        return
      }

      if (isEditing) {
        stopEditing(true)
      }

      // Сбрасываем скопированные ячейки при навигации
      if (copiedCells) {
        setCopiedCells(null)
      }

      const newRow = Math.max(
        0,
        Math.min(ROW_COUNT - 1, selectedCell.row + deltaRow)
      )
      const newCol = Math.max(
        0,
        Math.min(COL_COUNT - 1, selectedCell.col + deltaCol)
      )

      setSelectedCell({ row: newRow, col: newCol })
      // Сбрасываем множественное выделение при навигации
      setMultiSelection([])
    },
    [selectedCell, isEditing, stopEditing, copiedCells]
  )

  // Функция для очистки множества выделенных ячеек
  const handleClearMultipleCells = useCallback(() => {
    if (multiSelection.length === 0) return

    const sheetName = SHEET_NAMES[activeSheet]
    const cellsToDelete = getAllCellsInSelections(multiSelection)

    cellsToDelete.forEach(({ row, col }) => {
      multiSheetEngine.setCellValueWithoutRecalc(sheetName, row, col, '')
    })

    setUserEdited(true)
    updateRevision()
    multiSheetEngine.debouncedRecalc()
    setMultiSelection([])
  }, [multiSelection, activeSheet, multiSheetEngine, updateRevision])

  // Функция копирования выделенных ячеек
  const handleCopy = useCallback(
    async (isCut = false) => {
      if (!selectedCell && multiSelection.length === 0) return

      const sheetName = SHEET_NAMES[activeSheet]
      let cellsToCopy: { row: number; col: number }[] = []

      // Определяем какие ячейки копировать
      if (multiSelection.length > 0) {
        cellsToCopy = getAllCellsInSelections(multiSelection)
      } else if (selectedCell) {
        cellsToCopy = [selectedCell]
      }

      if (cellsToCopy.length === 0) return

      // Собираем данные ячеек
      const copiedData = cellsToCopy.map(({ row, col }) => ({
        row,
        col,
        value: String(multiSheetEngine.getCellValue(sheetName, row, col) || ''),
        rawValue: String(
          multiSheetEngine.getCellRawValue(sheetName, row, col) || ''
        ),
      }))

      // Сохраняем в state
      setCopiedCells({
        data: copiedData,
        sourceSheet: activeSheet,
        isCut,
      })

      // Подготавливаем данные для буфера обмена в формате TSV (Tab-Separated Values)
      // Находим границы выделения
      const minRow = Math.min(...cellsToCopy.map(c => c.row))
      const maxRow = Math.max(...cellsToCopy.map(c => c.row))
      const minCol = Math.min(...cellsToCopy.map(c => c.col))
      const maxCol = Math.max(...cellsToCopy.map(c => c.col))

      // Создаем двумерный массив для TSV
      const rows: string[][] = []
      for (let row = minRow; row <= maxRow; row++) {
        const rowData: string[] = []
        for (let col = minCol; col <= maxCol; col++) {
          const cellData = copiedData.find(c => c.row === row && c.col === col)
          rowData.push(cellData ? String(cellData.value) : '')
        }
        rows.push(rowData)
      }

      // Конвертируем в TSV строку
      const tsvData = rows.map(row => row.join('\t')).join('\n')

      // Копируем в буфер обмена
      try {
        await navigator.clipboard.writeText(tsvData)

        // Если это вырезание, очищаем ячейки
        if (isCut) {
          cellsToCopy.forEach(({ row, col }) => {
            multiSheetEngine.setCellValueWithoutRecalc(sheetName, row, col, '')
          })
          setUserEdited(true)
          updateRevision()
          multiSheetEngine.debouncedRecalc()
        }
      } catch (error) {
        console.error('Ошибка при копировании в буфер обмена:', error)
      }
    },
    [
      selectedCell,
      multiSelection,
      activeSheet,
      multiSheetEngine,
      updateRevision,
    ]
  )

  // Функция вставки из буфера обмена
  const handlePaste = useCallback(async () => {
    if (!selectedCell) return

    try {
      const clipboardText = await navigator.clipboard.readText()

      if (!clipboardText.trim()) return

      const sheetName = SHEET_NAMES[activeSheet]
      const startRow = selectedCell.row
      const startCol = selectedCell.col

      // Парсим TSV/CSV данные
      const rows = clipboardText.split('\n').filter(row => row !== '')
      const data: string[][] = rows.map(row => {
        // Поддерживаем как табуляции (TSV), так и запятые (CSV)
        if (row.includes('\t')) {
          return row.split('\t')
        } else {
          // Простой парсинг CSV (без учета кавычек с запятыми внутри)
          return row.split(',')
        }
      })

      if (data.length === 0) return

      // Вставляем данные
      let hasChanges = false
      for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
        for (let colIndex = 0; colIndex < data[rowIndex].length; colIndex++) {
          const targetRow = startRow + rowIndex
          const targetCol = startCol + colIndex

          // Проверяем границы
          if (targetRow >= ROW_COUNT || targetCol >= COL_COUNT) continue

          const cellValue = data[rowIndex][colIndex]

          // Устанавливаем значение ячейки
          multiSheetEngine.setCellValueWithoutRecalc(
            sheetName,
            targetRow,
            targetCol,
            cellValue
          )
          hasChanges = true
        }
      }

      if (hasChanges) {
        setUserEdited(true)
        updateRevision()
        multiSheetEngine.debouncedRecalc()
      }

      // Очищаем состояние копирования если это была операция вырезания
      if (copiedCells?.isCut) {
        setCopiedCells(null)
      }
    } catch (error) {
      console.error('Ошибка при вставке из буфера обмена:', error)
    }
  }, [selectedCell, activeSheet, multiSheetEngine, updateRevision, copiedCells])

  const handleKeyDown = useCallback(
    (e: React.KeyboardEvent) => {
      if (isEditing) return

      if (!selectedCell && e.key.match(/^(Arrow|Enter|F2|Delete|Backspace)$/)) {
        moveSelection(0, 0)
        e.preventDefault()
        return
      }
      if (!selectedCell) return

      const keyHandlers: Record<string, () => void> = {
        ArrowUp: () => moveSelection(-1, 0),
        ArrowDown: () => moveSelection(1, 0),
        ArrowLeft: () => moveSelection(0, -1),
        ArrowRight: () => moveSelection(0, 1),
        Enter: () => {
          setEditingSource('cell')
          startEditing()
        },
        F2: () => {
          setEditingSource('cell')
          startEditing()
        },
        Delete: () => {
          // Если есть множественное выделение, удаляем все выделенные ячейки
          if (multiSelection.length > 0) {
            handleClearMultipleCells()
          } else {
            handleClearCell()
          }
        },
        Backspace: () => {
          // Если есть множественное выделение, удаляем все выделенные ячейки
          if (multiSelection.length > 0) {
            handleClearMultipleCells()
          } else {
            handleClearCell()
          }
        },
        Escape: () => {
          // Сбрасываем множественное выделение
          setMultiSelection([])
        },
      }

      // Ctrl+A - выделить все ячейки
      if (e.key === 'a' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault()
        const allSelection = createSelectionFromRange(
          0,
          0,
          ROW_COUNT - 1,
          COL_COUNT - 1
        )
        setMultiSelection([allSelection])
        return
      }

      // Ctrl+C - копировать
      if (e.key === 'c' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault()
        handleCopy(false)
        return
      }

      // Ctrl+X - вырезать
      if (e.key === 'x' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault()
        handleCopy(true)
        return
      }

      // Ctrl+V - вставить
      if (e.key === 'v' && (e.ctrlKey || e.metaKey)) {
        e.preventDefault()
        handlePaste()
        return
      }

      if (keyHandlers[e.key]) {
        e.preventDefault()
        keyHandlers[e.key]()
      } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
        e.preventDefault()
        setEditingSource('cell')
        setEditingValue(e.key)
        setIsEditing(true)
        if (!userEdited) setUserEdited(true)
      }
    },
    [
      selectedCell,
      isEditing,
      moveSelection,
      startEditing,
      handleClearCell,
      multiSelection,
      handleClearMultipleCells,
      handleCopy,
      handlePaste,
    ]
  )

  const handleCellClick = useCallback(
    (row: number, col: number, event?: React.MouseEvent) => {
      if (isEditing) {
        stopEditing(true)
      }

      // Сбрасываем скопированные ячейки при клике на новую ячейку
      if (copiedCells) {
        setCopiedCells(null)
      }

      // Если удерживается Ctrl (или Cmd на Mac), добавляем к множественному выделению
      if (event && (event.ctrlKey || event.metaKey)) {
        const newSelection = createSelectionFromRange(row, col, row, col)
        setMultiSelection(prev => [...prev, newSelection])
        setSelectedCell({ row, col })
        return
      }

      // Если удерживается Shift, расширяем выделение
      if (event && event.shiftKey && selectedCell) {
        const newSelection = createSelectionFromRange(
          selectedCell.row,
          selectedCell.col,
          row,
          col
        )
        setMultiSelection([newSelection])
        return
      }

      // Обычный клик - очищаем множественное выделение
      setMultiSelection([])
      setSelectedCell({ row, col })
      // Не возвращаем фокус на контейнер, если он сейчас на formula bar
      if (document.activeElement !== formulaBarRef.current) {
        containerRefs.current[activeSheet]?.focus({ preventScroll: true })
      }
    },
    [isEditing, stopEditing, activeSheet, selectedCell, copiedCells]
  )

  // Новый обработчик для начала drag selection
  const handleCellMouseDown = useCallback(
    (row: number, col: number, event: React.MouseEvent) => {
      // Игнорируем правый клик
      if (event.button !== 0) return

      // Если удерживаются модификаторы, не начинаем drag
      if (event.ctrlKey || event.metaKey || event.shiftKey) return

      // Сбрасываем скопированные ячейки при drag selection
      if (copiedCells) {
        setCopiedCells(null)
      }

      setIsDragging(true)
      setDragStart({ row, col })
      setMultiSelection([])
      setSelectedCell({ row, col })
    },
    [copiedCells]
  )

  // Обработчик для drag selection
  const handleCellMouseEnter = useCallback(
    (row: number, col: number) => {
      if (!isDragging || !dragStart) return

      const newSelection = createSelectionFromRange(
        dragStart.row,
        dragStart.col,
        row,
        col
      )
      setMultiSelection([newSelection])
    },
    [isDragging, dragStart]
  )

  // Обработчик завершения drag selection
  const handleCellMouseUp = useCallback(() => {
    if (isDragging) {
      setIsDragging(false)
      setDragStart(null)
    }
  }, [isDragging])

  // Глобальный обработчик для завершения drag selection
  useEffect(() => {
    const handleGlobalMouseUp = () => {
      if (isDragging) {
        setIsDragging(false)
        setDragStart(null)
      }
    }

    if (isDragging) {
      document.addEventListener('mouseup', handleGlobalMouseUp)
      return () => {
        document.removeEventListener('mouseup', handleGlobalMouseUp)
      }
    }
  }, [isDragging])

  // Новый обработчик для кликов в режиме редактирования - вставляет ссылку
  const handleCellReferenceClick = useCallback(
    (targetSheetType: SheetType, row: number, col: number) => {
      if (!isEditing || !selectedCell || !editingValue.startsWith('=')) {
        stopEditing(true)
        setSelectedCell({ row, col })
        return
      }

      let cellReference: string

      if (targetSheetType !== activeSheet) {
        cellReference = createQualifiedCellReference(targetSheetType, row, col)
      } else {
        cellReference = createCellAddress(row, col)
      }

      const newValue = editingValue + cellReference
      setEditingValue(newValue)
      if (!userEdited) setUserEdited(true)

      if (editingSource === 'formula') {
        if (formulaBarRef.current) {
          formulaBarRef.current.value = newValue
          formulaBarRef.current.focus()
          const length = newValue.length
          formulaBarRef.current.setSelectionRange(length, length)
        }
      } else {
        if (activeCellInputRef.current) {
          activeCellInputRef.current.value = newValue
          activeCellInputRef.current.focus({ preventScroll: true })
          const length = newValue.length
          activeCellInputRef.current.setSelectionRange(length, length)
        }
      }
    },
    [isEditing, selectedCell, editingValue, activeSheet, editingSource]
  )

  const handleCellDoubleClick = useCallback(
    (row: number, col: number) => {
      setSelectedCell({ row, col })
      setEditingSource('cell')
      startEditing()
    },
    [startEditing]
  )

  const handleColumnResize = useCallback(
    (sheetType: SheetType, colIndex: number, newWidth: number) => {
      setColumnWidths(
        produce(draft => {
          draft[sheetType][colIndex] = Math.max(60, newWidth)
          const grid = gridRefs.current[sheetType]
          if (grid) {
            grid.resetAfterColumnIndex(colIndex)
          }
        })
      )
    },
    []
  )

  const handleFormulaBarChange = useCallback(
    (newValue: string) => {
      if (selectedCell) {
        if (!isEditing) setIsEditing(true)
        setEditingValue(newValue)
        if (!userEdited) setUserEdited(true)
      }
    },
    [selectedCell, isEditing, userEdited]
  )

  const handleFormulaBarFocus = useCallback(() => {
    if (selectedCell && !isEditing) {
      // Получаем позицию клика, если она была сохранена
      const clickPosition = formulaBarRef.current?.dataset.clickPosition
      const cursorPosition = clickPosition
        ? parseInt(clickPosition)
        : formulaBarRef.current?.selectionStart || 0

      setEditingSource('formula')
      startEditing()

      // Восстанавливаем позицию курсора после того как React обновит value
      setTimeout(() => {
        if (formulaBarRef.current) {
          if (document.activeElement !== formulaBarRef.current) {
            formulaBarRef.current.focus()
          }
          // Восстанавливаем вычисленную позицию курсора
          formulaBarRef.current.setSelectionRange(
            cursorPosition,
            cursorPosition
          )
          // Очищаем сохраненную позицию
          delete formulaBarRef.current.dataset.clickPosition
        }
      }, 0)
    }
  }, [selectedCell, isEditing, startEditing])

  const handleFormulaBarBlur = useCallback(
    (e: React.FocusEvent<HTMLInputElement>) => {
      // Проверяем, не переходит ли фокус в ячейку редактирования
      const relatedTarget = e.relatedTarget as HTMLElement
      if (relatedTarget && relatedTarget.closest('input[type="text"]')) {
        return // Не завершаем редактирование
      }
      // Завершаем редактирование только если фокус ушел полностью
      if (isEditing) {
        stopEditing(true)
      }
    },
    [isEditing, stopEditing]
  )

  const handleFormulaBarKeyDown = useCallback(
    (e: React.KeyboardEvent<HTMLInputElement>) => {
      if (e.key === 'Enter') {
        e.preventDefault()
        stopEditing(true)
        moveSelection(1, 0)
        setTimeout(() => {
          containerRefs.current[activeSheet]?.focus({ preventScroll: true })
        }, 0)
      } else if (e.key === 'Escape') {
        e.preventDefault()
        stopEditing(false)
        containerRefs.current[activeSheet]?.focus({ preventScroll: true })
      }
    },
    [stopEditing, moveSelection, activeSheet]
  )

  const onGridScroll = useCallback(
    (
      sheetType: SheetType,
      { scrollLeft, scrollTop }: { scrollLeft: number; scrollTop: number }
    ) => {
      if (headerRefs.current[sheetType]) {
        headerRefs.current[sheetType]!.scrollLeft = scrollLeft
      }
      if (rowHeaderRefs.current[sheetType]) {
        rowHeaderRefs.current[sheetType]!.scrollTop = scrollTop
      }
    },
    []
  )

  // Мемоизируем состояние ширин таблиц
  const [spreadsheetWidths, setSpreadsheetWidths] = useState({
    L: 0.5,
    R: 0.5,
  })

  // Мемоизируем опции автосохранения
  const autoSaveOptions = useMemo(
    () => ({
      templateId,
      autoSaveDelay: 4000,
      enableAutoSave: false, // Отключаем автосохранение по времени
    }),
    [templateId]
  )

  // Мемоизируем getAllModifiedCells для предотвращения частых ререндеров хука автосохранения
  const memoizedGetAllModifiedCells = useCallback(
    multiSheetEngine.getAllModifiedCells,
    [revision] // Используем revision вместо функции для более стабильной мемоизации
  )

  // Используем новый хук автосохранения
  const {
    isSaving,
    isLoading,
    hasUnsavedChanges,
    lastSaveError,
    manualSave,
    clearError,
    loadSheets,
  } = useSheetAutoSave(
    memoizedGetAllModifiedCells,
    multiSheetEngine.isCalculating,
    revision,
    autoSaveOptions
  )

  // Используем ref для стабильного API
  const engineAPIRef = useRef<any>(null)

  // Мемоизируем объект для передачи родительскому компоненту
  const engineAPI = useMemo(
    () => ({
      ...multiSheetEngine,
      updateRevision,
      hasUnsavedChanges,
      isSaving,
      manualSave,
    }),
    [multiSheetEngine, updateRevision, hasUnsavedChanges, isSaving, manualSave]
  )

  // Обновляем ref только при значимых изменениях
  useEffect(() => {
    if (engineAPIRef.current) {
      engineAPIRef.current.hasUnsavedChanges = hasUnsavedChanges
      engineAPIRef.current.isSaving = isSaving
      engineAPIRef.current.manualSave = manualSave
    } else {
      engineAPIRef.current = engineAPI
    }
  }, [hasUnsavedChanges, isSaving, manualSave, engineAPI])

  // Передаем методы движка родительскому компоненту - только один раз после инициализации
  useEffect(() => {
    if (onEngineReady && isInitialized && engineAPIRef.current) {
      onEngineReady(engineAPIRef.current)
    }
  }, [onEngineReady, isInitialized]) // Убираем engineAPI из зависимостей

  // Используем хук для перетаскивания разделителя
  const handleDividerDrag = useCallback((newLeftPercentage: number) => {
    // Используем requestAnimationFrame для более плавного обновления
    requestAnimationFrame(() => {
      setSpreadsheetWidths({
        L: newLeftPercentage,
        R: 1 - newLeftPercentage,
      })
    })
  }, [])

  const separatorRef = useDraggableDivider(handleDividerDrag)

  // Мемоизируем функцию инициализации данных
  const initializeData = useCallback(async () => {
    if (!templateId || isInitialized) return

    let finalBaseData: Record<string, Record<string, any>> = {}

    // 1. ИСПОЛЬЗУЕМ ДАННЫЕ ИЗ REACT QUERY КЕША
    if (fileData && Object.keys(fileData.data).length > 0) {
      finalBaseData = { [SHEET_NAMES.report]: fileData.data }
      setBaseFileData(finalBaseData)
      setTemplateData(finalBaseData)
    }

    // 2. ИСПОЛЬЗУЕМ templateData КАК FALLBACK или основные данные
    const hasTemplateData =
      Object.keys(templateData).length > 0 &&
      Object.values(templateData).some(sheet => Object.keys(sheet).length > 0)

    if (hasTemplateData && Object.keys(finalBaseData).length === 0) {
      finalBaseData = templateData
      setBaseFileData(finalBaseData)
      setTemplateData(templateData)
    }

    // 3. ЗАГРУЖАЕМ ПОЛЬЗОВАТЕЛЬСКИЕ ИЗМЕНЕНИЯ ИЗ API
    try {
      const apiSheets = await loadSheets()

      // Преобразуем листы API в формат данных
      const userChanges: Record<string, Record<string, any>> = {}
      Object.entries(apiSheets).forEach(([sheetName, sheet]) => {
        // Нормализуем имя листа: "Report" -> "L"
        const normalizedName =
          sheetName === 'Report'
            ? SHEET_NAMES.report
            : sheetName === 'Calculations'
              ? SHEET_NAMES.calculations
              : sheetName

        // Интересуют только листы L и R
        if (
          (normalizedName === SHEET_NAMES.report ||
            normalizedName === SHEET_NAMES.calculations) &&
          sheet.cells &&
          Object.keys(sheet.cells).length > 0
        ) {
          userChanges[normalizedName] = sheet.cells
        }
      })

      // 4. ОБЪЕДИНЯЕМ БАЗОВЫЕ ДАННЫЕ С ПОЛЬЗОВАТЕЛЬСКИМИ ИЗМЕНЕНИЯМИ
      if (Object.keys(userChanges).length > 0) {
        // Создаем объединенные данные: базовые данные файла + пользовательские изменения
        const mergedData: Record<string, Record<string, any>> = {}

        // Копируем базовые данные файла как основу
        Object.entries(finalBaseData).forEach(([sheetName, sheetData]) => {
          mergedData[sheetName] = { ...sheetData }
        })

        // Применяем пользовательские изменения поверх базовых данных
        Object.entries(userChanges).forEach(([sheetName, sheetData]) => {
          if (!mergedData[sheetName]) {
            mergedData[sheetName] = {}
          }
          Object.entries(sheetData).forEach(([cellAddress, value]) => {
            mergedData[sheetName][cellAddress] = value
          })
        })

        multiSheetEngine.loadData(mergedData)
      } else if (Object.keys(finalBaseData).length > 0) {
        multiSheetEngine.loadData(finalBaseData)
      }
    } catch (error) {
      console.error('❌ Ошибка при загрузке пользовательских изменений:', error)

      // В случае ошибки используем только базовые данные
      if (Object.keys(finalBaseData).length > 0) {
        multiSheetEngine.loadData(finalBaseData)
      }
    }

    setIsInitialized(true)
  }, [
    templateId,
    templateData,
    fileData,
    loadSheets,
    multiSheetEngine,
    setTemplateData,
    isInitialized,
  ])

  // Загружаем сохраненные формулы при инициализации
  // Ждем загрузки данных из React Query перед инициализацией
  useEffect(() => {
    // Инициализируем только когда все данные загружены или их нет вообще
    const canInitialize =
      !isLoadingLatestFile && !isLoadingFileData && templateId && !isInitialized

    if (canInitialize) {
      initializeData()
    }
  }, [
    initializeData,
    isLoadingLatestFile,
    isLoadingFileData,
    templateId,
    isInitialized,
  ])

  return (
    <div className="flex h-full flex-col bg-background">
      <FormulaBar
        selectedCell={selectedCell}
        formulaBarValue={formulaBarValue}
        isCalculating={multiSheetEngine.isCalculating}
        isEditing={isEditing}
        onValueChange={handleFormulaBarChange}
        onFocus={handleFormulaBarFocus}
        onBlur={handleFormulaBarBlur}
        onKeyDown={handleFormulaBarKeyDown}
        formulaBarRef={el => {
          formulaBarRef.current = el
        }}
        isSaving={isSaving}
        isLoading={isLoading}
        hasUnsavedChanges={hasUnsavedChanges}
        lastSaveError={lastSaveError}
        onManualSave={manualSave}
        onClearError={clearError}
        excelFileName={excelFileName}
        isExcelLoading={isExcelLoading}
        onExcelFileChange={onExcelFileChange}
      />
      <div
        className="flex min-w-0 flex-1 gap-1 overflow-hidden"
        style={{ transition: 'none' }}
      >
        {SHEET_TYPES.map((sheetType, index) => (
          <React.Fragment key={sheetType}>
            <Spreadsheet
              sheetType={sheetType}
              columnWidths={columnWidths[sheetType]}
              spreadsheetWidths={spreadsheetWidths}
              getCachedCellData={getCachedCellData}
              selectedCell={selectedCell}
              multiSelection={multiSelection}
              activeSheet={activeSheet}
              isEditing={isEditing}
              editingValue={editingValue}
              highlightedCells={highlightedCells}
              handleCellClick={handleCellClick}
              handleCellDoubleClick={handleCellDoubleClick}
              handleCellChange={handleCellChange}
              handleCellReferenceClick={handleCellReferenceClick}
              handleCellMouseDown={handleCellMouseDown}
              handleCellMouseEnter={handleCellMouseEnter}
              handleCellMouseUp={handleCellMouseUp}
              isInEditMode={isEditing}
              stopEditing={stopEditing}
              setActiveSheet={setActiveSheet}
              activeCellInputRef={activeCellInputRef}
              containerRefs={containerRefs}
              handleKeyDown={handleKeyDown}
              headerRefs={headerRefs}
              rowHeaderRefs={rowHeaderRefs}
              gridRefs={gridRefs}
              onGridScroll={onGridScroll}
              handleColumnResize={handleColumnResize}
              mergedCells={mergedCells}
              copiedCells={copiedCells}
            />
            {index === 0 && (
              <div
                ref={separatorRef}
                className="flex w-2 cursor-col-resize items-center justify-center bg-border transition-colors hover:bg-primary/20"
                style={{ userSelect: 'none' }}
              >
                <div className="h-4 w-0.5 rounded-full bg-muted-foreground/50" />
              </div>
            )}
          </React.Fragment>
        ))}
      </div>
    </div>
  )
}

export default DualSpreadsheet
