import { useCallback, useEffect, useRef, useState } from 'react'
import { CellValue, Workbook } from '../feature/excelEngine/excelEngine'
interface SheetConfig {
  name: string
  rows: number
  cols: number
}

interface UseMultiSheetEngineProps {
  sheets: SheetConfig[]
  initialData?: Record<string, Record<string, any>>
}

export function useMultiSheetEngine({
  sheets,
  initialData = {},
}: UseMultiSheetEngineProps) {
  const workbookRef = useRef<Workbook | null>(null)
  const [isCalculating, setIsCalculating] = useState(false)
  const [revision, setRevision] = useState(0) // Новый счетчик для обновлений
  const debouncedRecalcTimeoutRef = useRef<NodeJS.Timeout | null>(null)
  const isRecalculatingRef = useRef(false)

  // Храним изначальные данные шаблона для сравнения
  const templateDataRef = useRef<Record<string, Record<string, any>>>({})

  // Безопасная функция для вычислений
  const safeRecalc = useCallback(() => {
    if (!workbookRef.current || isRecalculatingRef.current) return

    isRecalculatingRef.current = true
    setIsCalculating(true)

    try {
      workbookRef.current.recalc()
    } catch (error) {
      console.warn('Ошибка при вычислении:', error)
    } finally {
      // Уменьшаем задержку для быстрого отклика
      setTimeout(() => {
        setIsCalculating(false)
        isRecalculatingRef.current = false
        // Увеличиваем ревизию, чтобы сообщить компонентам о необходимости обновления
        setRevision(r => r + 1)
      }, 50) // Уменьшено с 150ms до 50ms
    }
  }, [])

  // Инициализация workbook и листов
  useEffect(() => {
    if (!workbookRef.current) {
      workbookRef.current = new Workbook()

      // Создаем листы
      sheets.forEach(sheetConfig => {
        workbookRef.current!.addSheet(sheetConfig.name)
      })

      // Увеличиваем ревизию для начальной отрисовки
      setRevision(r => r + 1)
    }
  }, [sheets])

  // Ссылка для отслеживания уже загруженных данных
  const loadedDataRef = useRef<string>('')

  // Отдельный useEffect для перезагрузки данных при изменении initialData
  useEffect(() => {
    if (!workbookRef.current) return

    // Предотвращаем случайную очистку данных при смене вкладки
    if (document.hidden) return

    // Создаем ключ для проверки изменений данных
    const dataKey = JSON.stringify(initialData)

    // Если данные уже загружены, не перезагружаем их
    if (
      loadedDataRef.current === dataKey &&
      Object.keys(initialData).length > 0
    )
      return

    if (Object.keys(initialData).length > 0) {
      // Очищаем только те листы, для которых есть новые данные
      for (const sheetName of Object.keys(initialData)) {
        const sheet = workbookRef.current.getSheet(sheetName)
        if (sheet) {
          sheet.cells.clear()
        }
      }

      workbookRef.current.fromJSON(initialData)
      loadedDataRef.current = dataKey // Сохраняем ключ загруженных данных
      safeRecalc()
    } else {
      // Если данных нет, просто обновляем ревизию
      setRevision(r => r + 1)
    }
  }, [initialData, safeRecalc])

  // Отложенный пересчет с дебаунсом
  const debouncedRecalc = useCallback(() => {
    if (!workbookRef.current || isRecalculatingRef.current) return

    // Очищаем предыдущий отложенный пересчет
    if (debouncedRecalcTimeoutRef.current) {
      clearTimeout(debouncedRecalcTimeoutRef.current)
    }

    // Уменьшаем задержку для быстрого отклика
    debouncedRecalcTimeoutRef.current = setTimeout(() => {
      safeRecalc()
    }, 100) // Уменьшено с 300ms до 100ms
  }, [safeRecalc])

  // Функция для немедленного обновления интерфейса без пересчета
  const updateRevision = useCallback(() => {
    setRevision(r => r + 1)
  }, [])

  // Установка значения ячейки без немедленного пересчета
  const setCellValueWithoutRecalc = useCallback(
    (sheetName: string, row: number, col: number, value: string) => {
      if (!workbookRef.current || isRecalculatingRef.current) return

      const cellName = columnToLabel(col) + (row + 1)
      const qualifiedName = `${sheetName}!${cellName}`

      // Конвертируем пустую строку в null
      const cellValue: CellValue = value === '' ? null : value

      // Если значение начинается с =, то это формула
      if (typeof cellValue === 'string' && cellValue.startsWith('=')) {
        workbookRef.current.setCell(qualifiedName, cellValue)
      } else {
        // Пытаемся конвертировать в число, если возможно
        const numValue = Number(cellValue)
        if (!isNaN(numValue) && cellValue !== null && cellValue !== '') {
          workbookRef.current.setCell(qualifiedName, numValue)
        } else {
          workbookRef.current.setCell(qualifiedName, cellValue)
        }
      }
    },
    []
  )

  // Установка значения ячейки с немедленным пересчетом
  const setCellValue = useCallback(
    (sheetName: string, row: number, col: number, value: string) => {
      if (!workbookRef.current || isRecalculatingRef.current) return

      const cellName = columnToLabel(col) + (row + 1)
      const qualifiedName = `${sheetName}!${cellName}`

      // Конвертируем пустую строку в null
      const cellValue: CellValue = value === '' ? null : value

      // Если значение начинается с =, то это формула
      if (typeof cellValue === 'string' && cellValue.startsWith('=')) {
        workbookRef.current.setCell(qualifiedName, cellValue)
      } else {
        // Пытаемся конвертировать в число, если возможно
        const numValue = Number(cellValue)
        if (!isNaN(numValue) && cellValue !== null && cellValue !== '') {
          workbookRef.current.setCell(qualifiedName, numValue)
        } else {
          workbookRef.current.setCell(qualifiedName, cellValue)
        }
      }

      // Запускаем отложенный пересчет с дебаунсом (избегаем двойного пересчёта)
      debouncedRecalc()
    },
    [debouncedRecalc]
  )

  // Получение значения ячейки (вычисленное)
  const getCellValue = useCallback(
    (sheetName: string, row: number, col: number): CellValue => {
      if (!workbookRef.current) return ''

      const cellName = columnToLabel(col) + (row + 1)
      const qualifiedName = `${sheetName}!${cellName}`

      return workbookRef.current.getValue(qualifiedName)
    },
    []
  )

  // Получение сырого значения ячейки (формула)
  const getCellRawValue = useCallback(
    (sheetName: string, row: number, col: number): string => {
      if (!workbookRef.current) return ''

      const sheet = workbookRef.current.getSheet(sheetName)
      if (!sheet) return ''

      const cellName = columnToLabel(col) + (row + 1)
      const cell = sheet.getCell(cellName)

      return String(cell.raw || '')
    },
    []
  )

  // Получение всех измененных ячеек для листа
  const getModifiedCells = useCallback(
    (sheetName: string): Record<string, CellValue> => {
      if (!workbookRef.current) return {}

      const sheet = workbookRef.current.getSheet(sheetName)
      if (!sheet) return {}

      return sheet.toJSON()
    },
    []
  )

  // Установка изначальных данных шаблона
  const setTemplateData = useCallback(
    (data: Record<string, Record<string, any>>) => {
      templateDataRef.current = JSON.parse(JSON.stringify(data)) // Глубокая копия
    },
    []
  )

  // Получение всех измененных ячеек для всех листов (только пользовательские изменения)
  const getAllModifiedCells = useCallback((): Record<
    string,
    Record<string, CellValue>
  > => {
    if (!workbookRef.current) return {}

    const allData = workbookRef.current.toJSON()
    const modifiedData: Record<string, Record<string, CellValue>> = {}

    // Список всех листов (из движка или baseline)
    const sheetNamesSet = new Set([
      ...Object.keys(allData),
      ...Object.keys(templateDataRef.current),
    ])

    sheetNamesSet.forEach(sheetName => {
      const sheetData = allData[sheetName] || {}
      const templateSheet = templateDataRef.current[sheetName] || {}

      const cellAddresses = new Set([
        ...Object.keys(sheetData),
        ...Object.keys(templateSheet),
      ])

      const modifiedSheet: Record<string, CellValue> = {}

      cellAddresses.forEach(cellAddress => {
        const currentVal = sheetData[cellAddress] ?? ''
        const templateVal = templateSheet[cellAddress] ?? ''

        const normalizeValue = (val: any): string => {
          if (val === null || val === undefined) return ''
          const str = String(val).trim()
          if (str === '0' || str === '') return ''
          return str
        }

        const normalizedCurrent = normalizeValue(currentVal)
        const normalizedTemplate = normalizeValue(templateVal)

        if (normalizedCurrent !== normalizedTemplate) {
          // Если текущего значения нет (ячейка очищена), отправляем ''
          modifiedSheet[cellAddress] = currentVal
        }
      })

      if (Object.keys(modifiedSheet).length > 0) {
        modifiedData[sheetName] = modifiedSheet
      }
    })

    return modifiedData
  }, [])

  // Очистка всех данных
  const clearAllData = useCallback(() => {
    if (!workbookRef.current) return

    workbookRef.current.clear()
    setRevision(r => r + 1)
  }, [])

  // Загрузка данных из JSON
  const loadData = useCallback(
    (data: Record<string, Record<string, any>>) => {
      if (!workbookRef.current) return

      workbookRef.current.fromJSON(data)
      safeRecalc()
    },
    [safeRecalc]
  )

  // Пересчет всех формул
  const recalculate = useCallback(() => {
    safeRecalc()
  }, [safeRecalc])

  // Очистка таймаутов при размонтировании
  useEffect(() => {
    return () => {
      if (debouncedRecalcTimeoutRef.current) {
        clearTimeout(debouncedRecalcTimeoutRef.current)
      }
      isRecalculatingRef.current = false
    }
  }, [])

  return {
    setCellValue,
    setCellValueWithoutRecalc,
    debouncedRecalc,
    updateRevision, // Добавляем новую функцию
    getCellValue,
    getCellRawValue,
    getModifiedCells,
    getAllModifiedCells,
    setTemplateData, // Экспортируем функцию установки данных шаблона
    clearAllData,
    loadData,
    recalculate,
    isCalculating,
    workbook: workbookRef.current,
    revision, // Экспортируем ревизию
  }
}

// Вспомогательная функция для конвертации индекса колонки в букву
function columnToLabel(index: number): string {
  return String.fromCharCode(65 + index)
}
