import { useMultiSheetEngine } from '@/hook/useMultiSheetEngine'
import { useSheetAutoSave } from '@/hook/useSheetAutoSave'
import { getFileData, getLatestFileForTemplate } from '@/service/fileApiSevice'
import { produce } from 'immer'
import { FC, useCallback, useEffect, useMemo, useRef, useState } from 'react'

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

const DualSpreadsheet: FC<DualSpreadsheetProps> = ({
  templateData = {},
  mergedCells = [],
  templateId,
  onEngineReady,
}) => {
  const { revision, updateRevision, setTemplateData, ...multiSheetEngine } =
    useMultiSheetEngine({
      sheets: [
        { name: SHEET_NAMES.report, rows: ROW_COUNT, cols: COL_COUNT },
        { name: SHEET_NAMES.calculations, rows: ROW_COUNT, cols: COL_COUNT },
      ],
      initialData: templateData || {},
    })

  // Передаем методы движка родительскому компоненту
  useEffect(() => {
    if (onEngineReady) {
      onEngineReady({
        ...multiSheetEngine,
        updateRevision,
      })
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [onEngineReady])

  const [activeSheet, setActiveSheet] = useState<SheetType>('report')
  const [selectedCell, setSelectedCell] = useState<{
    row: number
    col: number
  } | null>(null)
  const [isEditing, setIsEditing] = useState(false)
  const [editingValue, setEditingValue] = useState<string>('') // Локальное значение во время редактирования
  const [isInitialized, setIsInitialized] = useState(false)
  const [baseFileData, setBaseFileData] = useState<
    Record<string, Record<string, any>>
  >({}) // Базовые данные файла

  const [columnWidths, setColumnWidths] = useState<Record<SheetType, number[]>>(
    () => ({
      report: Array(COL_COUNT).fill(96),
      calculations: Array(COL_COUNT).fill(96),
    })
  )
  const gridRefs = useRef<Record<SheetType, any>>({
    report: null,
    calculations: null,
  })

  const containerRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
    report: null,
    calculations: null,
  })
  const activeCellInputRef = useRef<HTMLInputElement>(null)
  const formulaBarRef = useRef<HTMLInputElement | null>(null)
  const headerRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
    report: null,
    calculations: null,
  })
  const rowHeaderRefs = useRef<Record<SheetType, HTMLDivElement | null>>({
    report: null,
    calculations: null,
  })
  const initialTemplateValues = useRef<Record<string, string>>({})

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

  useEffect(() => {
    // Используем baseFileData как источник базовых значений для сравнения
    const reportBaseData = baseFileData?.[SHEET_NAMES.report]

    if (reportBaseData && Object.keys(reportBaseData).length > 0) {
      // Очищаем старые значения
      initialTemplateValues.current = {}

      Object.entries(reportBaseData).forEach(([cellName, value]) => {
        initialTemplateValues.current[cellName] = String(value)
      })

      console.log(
        '✅ Загружено базовых значений файла для сравнения:',
        Object.keys(initialTemplateValues.current).length
      )
    } else {
      // Fallback: используем templateData, если baseFileData еще не загружен
      const reportTemplate = templateData?.[SHEET_NAMES.report]

      if (reportTemplate && Object.keys(reportTemplate).length > 0) {
        // Очищаем старые значения
        initialTemplateValues.current = {}

        Object.entries(reportTemplate).forEach(([cellName, value]) => {
          initialTemplateValues.current[cellName] = String(value)
        })

        console.log(
          '✅ Загружено значений templateData для сравнения (fallback):',
          Object.keys(initialTemplateValues.current).length
        )
      } else {
        console.log('⚠️ DualSpreadsheet: Нет базовых данных для сравнения')
      }
    }
  }, [baseFileData, templateData])

  useEffect(() => {
    if (selectedCell && activeSheet) {
      const grid = gridRefs.current[activeSheet]
      grid?.scrollToItem({
        rowIndex: selectedCell.row,
        columnIndex: selectedCell.col,
        align: 'auto',
      })
    }
  }, [selectedCell, activeSheet])

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

      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] ?? '' // Базовое значение из файла

          // Отладка только для измененных ячеек
          if (
            sheetType === 'report' &&
            baseFileValue &&
            rawValue !== baseFileValue
          ) {
            console.log(`🔧 Измененная ячейка ${cellName}:`, {
              baseFileValue,
              rawValue,
              isModified: true,
            })
          }

          // Нормализуем значения для сравнения
          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

          // Отладка только для измененных ячеек
          if (sheetType === 'report' && isModified) {
            console.log(`🔍 Измененная ячейка ${cellName}:`, {
              baseFileValue,
              rawValue,
              isModified,
            })
          }

          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 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 и ячейкой при редактировании
  useEffect(() => {
    if (isEditing && formulaBarRef.current) {
      formulaBarRef.current.value = editingValue
    }
  }, [editingValue, isEditing])

  const startEditing = useCallback(() => {
    if (!selectedCell) return
    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]
        const cellName =
          getColumnLabel(selectedCell.col) + (selectedCell.row + 1)
        const oldValue = multiSheetEngine.getCellRawValue(
          sheetName,
          selectedCell.row,
          selectedCell.col
        )
        const baseFileValue = initialTemplateValues.current[cellName] ?? '' // Базовое значение из файла

        console.log('💾 Сохранение ячейки:', {
          cellName,
          oldValue,
          newValue: editingValue,
          baseFileValue,
          isChanged: oldValue !== editingValue,
          isModifiedFromBaseFile: baseFileValue !== editingValue,
        })

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

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

  const handleClearCell = useCallback(() => {
    if (!selectedCell) return
    const sheetName = SHEET_NAMES[activeSheet]
    multiSheetEngine.setCellValueWithoutRecalc(
      sheetName,
      selectedCell.row,
      selectedCell.col,
      ''
    )
    updateRevision()
    multiSheetEngine.debouncedRecalc()
  }, [activeSheet, selectedCell, multiSheetEngine, updateRevision])

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

      if (isEditing) {
        stopEditing(true)
      }

      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 })
    },
    [selectedCell, isEditing, stopEditing]
  )

  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: () => startEditing(),
        F2: () => startEditing(),
        Delete: handleClearCell,
        Backspace: handleClearCell,
      }

      if (keyHandlers[e.key]) {
        e.preventDefault()
        keyHandlers[e.key]()
      } else if (e.key.length === 1 && !e.ctrlKey && !e.metaKey) {
        e.preventDefault()
        setEditingValue(e.key)
        setIsEditing(true)
      }
    },
    [selectedCell, isEditing, moveSelection, startEditing, handleClearCell]
  )

  const handleCellClick = useCallback(
    (row: number, col: number) => {
      if (isEditing) {
        stopEditing(true)
      }
      setSelectedCell({ row, col })
      containerRefs.current[activeSheet]?.focus({ preventScroll: true })
    },
    [isEditing, stopEditing, activeSheet]
  )

  const handleCellDoubleClick = useCallback(
    (row: number, col: number) => {
      setSelectedCell({ row, col })
      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)
      }
    },
    [selectedCell, isEditing]
  )

  const handleFormulaBarFocus = useCallback(() => {
    if (selectedCell && !isEditing) {
      startEditing()
    }
  }, [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 {
    isSaving,
    isLoading,
    hasUnsavedChanges,
    lastSaveError,
    manualSave,
    clearError,
    loadSavedSheets,
    loadSheets, // Добавляем асинхронную функцию загрузки
  } = useSheetAutoSave(
    multiSheetEngine.getAllModifiedCells,
    multiSheetEngine.isCalculating,
    revision,
    {
      templateId,
      autoSaveDelay: 2000,
      enableAutoSave: true,
    }
  )

  // Отладка templateId
  useEffect(() => {
    console.log('🆔 Текущий templateId в DualSpreadsheet:', {
      templateId,
      type: typeof templateId,
      isValid: templateId
        ? /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
            templateId
          )
        : false,
    })
  }, [templateId])

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

  const separatorRef = useDraggableDivider(handleDividerDrag)

  // Загружаем сохраненные формулы при инициализации
  useEffect(() => {
    if (!templateId || isInitialized) return

    // Асинхронная функция для загрузки и слияния данных
    const initializeData = async () => {
      let finalBaseData: Record<string, Record<string, any>> = {}

      // 1. ЗАГРУЖАЕМ БАЗОВЫЕ ДАННЫЕ ФАЙЛА
      if (templateId) {
        try {
          console.log('🔍 Ищем файлы для templateId:', templateId)
          const latestFile = await getLatestFileForTemplate(templateId)

          if (latestFile) {
            console.log(
              '📄 Найден файл:',
              latestFile.name,
              'ID:',
              latestFile.id
            )
            const fileData = await getFileData(latestFile.id)

            // TODO: Пока getFileData возвращает пустые данные, используем templateData
            // Когда API будет готов, здесь будут реальные данные файла
            if (Object.keys(fileData.data).length > 0) {
              finalBaseData = { [SHEET_NAMES.report]: fileData.data }
              setBaseFileData(finalBaseData)
              // Сохраняем baseline, чтобы в L попадали только пользовательские изменения
              setTemplateData(finalBaseData)
              console.log('📄 Загружены базовые данные файла:', finalBaseData)
            } else {
              console.log(
                '⚠️ getFileData вернул пустые данные, используем templateData'
              )
            }
          } else {
            console.log('⚠️ Файл не найден для templateId:', templateId)
          }
        } catch (error) {
          console.error('❌ Ошибка при загрузке данных файла:', error)
        }
      }

      // 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)
        console.log(
          '📄 Используем templateData как базовые данные:',
          finalBaseData
        )
        setTemplateData(templateData)
      }

      // 3. ЗАГРУЖАЕМ ПОЛЬЗОВАТЕЛЬСКИЕ ИЗМЕНЕНИЯ ИЗ API
      try {
        console.log('🔍 Загружаем пользовательские изменения из API...')
        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
          }
        })

        console.log(
          '📂 Загружены пользовательские изменения:',
          Object.keys(userChanges)
        )

        // 4. ОБЪЕДИНЯЕМ БАЗОВЫЕ ДАННЫЕ С ПОЛЬЗОВАТЕЛЬСКИМИ ИЗМЕНЕНИЯМИ
        if (Object.keys(userChanges).length > 0) {
          console.log(
            '🔄 Объединяем базовые данные с пользовательскими изменениями'
          )

          // Создаем объединенные данные: базовые данные файла + пользовательские изменения
          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
            })
          })

          console.log(
            '📊 Загружаем объединенные данные (базовые + пользовательские)'
          )
          multiSheetEngine.loadData(mergedData)

          // Обновляем baseline, включая уже сохранённые изменения пользователя,
          // чтобы их не сохранять повторно
        } else if (Object.keys(finalBaseData).length > 0) {
          console.log(
            '📋 Используем только базовые данные (нет пользовательских изменений)'
          )
          multiSheetEngine.loadData(finalBaseData)
        } else {
          console.log('⚠️ Нет данных для загрузки')
        }
      } catch (error) {
        console.error(
          '❌ Ошибка при загрузке пользовательских изменений:',
          error
        )

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

      setIsInitialized(true)
    }

    initializeData()
  }, [
    templateId,
    templateData,
    loadSheets,
    multiSheetEngine,
    setTemplateData,
    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}
      />
      <div
        className="flex min-w-0 flex-1 gap-1 overflow-hidden"
        style={{ transition: 'none' }}
      >
        {SHEET_TYPES.map((sheetType, index) => (
          <Spreadsheet
            key={sheetType}
            sheetType={sheetType}
            columnWidths={columnWidths[sheetType]}
            spreadsheetWidths={spreadsheetWidths}
            getCachedCellData={getCachedCellData}
            selectedCell={selectedCell}
            activeSheet={activeSheet}
            isEditing={isEditing}
            editingValue={editingValue}
            handleCellClick={handleCellClick}
            handleCellDoubleClick={handleCellDoubleClick}
            handleCellChange={handleCellChange}
            stopEditing={stopEditing}
            setActiveSheet={setActiveSheet}
            activeCellInputRef={activeCellInputRef}
            containerRefs={containerRefs}
            handleKeyDown={handleKeyDown}
            headerRefs={headerRefs}
            rowHeaderRefs={rowHeaderRefs}
            gridRefs={gridRefs}
            onGridScroll={onGridScroll}
            handleColumnResize={handleColumnResize}
            mergedCells={mergedCells}
          />
        ))}
        <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>
      </div>
    </div>
  )
}

export default DualSpreadsheet
