import { produce } from 'immer'
import {
  FC,
  memo,
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react'
import { useMultiSheetEngine } from '../../hooks/useMultiSheetEngine'

const ROW_COUNT = 90
const COL_COUNT = 20
const ROW_HEIGHT = 28

const SHEET_NAMES = {
  report: 'L',
  calculations: 'R',
} as const

type SheetType = keyof typeof SHEET_NAMES

// --- Helper Functions ---
const getColumnLabel = (index: number) => String.fromCharCode(65 + index)

// --- Interfaces ---
interface DualSpreadsheetProps {
  templateData?: Record<string, Record<string, any>>
}

// --- Child Components ---
interface CellProps {
  sheetType: SheetType
  rowIndex: number
  colIndex: number
  columnWidth: number
  isSelected: boolean
  isEditing: boolean
  displayValue: string // Отображаемое значение (вычисленное)
  rawValue: string // "Сырое" значение (формула)
  isModified: boolean
  onCellClick: (row: number, col: number) => void
  onCellDoubleClick: (row: number, col: number) => void
  onCellValueChange: (newValue: string) => void // Изменение значения во время редактирования
  stopEditing: (save: boolean) => void
  setActiveSheet: (type: SheetType) => void
  activeCellRef: React.RefObject<HTMLInputElement>
}

const Cell = memo(
  ({
    sheetType,
    rowIndex,
    colIndex,
    columnWidth,
    isSelected,
    isEditing,
    displayValue,
    rawValue,
    isModified,
    onCellClick,
    onCellDoubleClick,
    onCellValueChange,
    stopEditing,
    setActiveSheet,
    activeCellRef,
  }: CellProps) => {
    const className = `border border-border ${isSelected ? 'bg-accent' : ''} ${
      isModified ? 'bg-yellow-50' : ''
    }`

    const style = {
      minWidth: `${columnWidth}px`,
      width: `${columnWidth}px`,
      height: `${ROW_HEIGHT}px`,
      overflow: 'hidden',
      padding: 0,
      position: 'relative' as const,
    }

    const handleClick = useCallback(() => {
      setActiveSheet(sheetType)
      onCellClick(rowIndex, colIndex)
    }, [setActiveSheet, sheetType, onCellClick, rowIndex, colIndex])

    const handleDoubleClick = useCallback(
      () => onCellDoubleClick(rowIndex, colIndex),
      [onCellDoubleClick, rowIndex, colIndex],
    )

    return (
      <td
        className={className}
        style={style}
        onClick={handleClick}
        onDoubleClick={handleDoubleClick}
      >
        {isEditing && isSelected ? (
          <input
            ref={activeCellRef}
            type="text"
            value={rawValue} // Во время редактирования показываем "сырое" значение
            onChange={(e) => onCellValueChange(e.target.value)}
            onBlur={() => stopEditing(true)}
            onKeyDown={(e) => {
              if (e.key === 'Enter') {
                e.preventDefault()
                stopEditing(true)
              } else if (e.key === 'Escape') {
                e.preventDefault()
                stopEditing(false)
              }
            }}
            className="absolute left-0 top-0 z-20 box-border h-full w-full border-2 border-primary px-2 py-1"
          />
        ) : (
          <div
            className="relative h-full w-full truncate px-2 py-1"
            style={
              isSelected
                ? { boxShadow: 'inset 0 0 0 2px hsl(var(--primary))' }
                : {}
            }
          >
            {displayValue}
          </div>
        )}
      </td>
    )
  },
)

interface FormulaBarProps {
  sheetType: SheetType
  activeSheet: SheetType
  selectedCell: { row: number; col: number } | null
  formulaBarValue: string
  isCalculating: boolean
  isEditing: boolean
  onValueChange: (value: string) => void
  onFocus: () => void
  onBlur: () => void
  onKeyDown: (e: React.KeyboardEvent<HTMLInputElement>) => void
  formulaBarRef: (el: HTMLInputElement | null) => void
}

const FormulaBar = memo(
  ({
    sheetType,
    activeSheet,
    selectedCell,
    formulaBarValue,
    isCalculating,
    isEditing,
    onValueChange,
    onFocus,
    onBlur,
    onKeyDown,
    formulaBarRef,
  }: FormulaBarProps) => {
    if (activeSheet !== sheetType) {
      return (
        <div className="flex-shrink-0 border-b bg-background px-3 py-1">
          <div className="flex h-[28px] items-center" />
        </div>
      )
    }

    return (
      <div className="flex-shrink-0 border-b bg-background px-3 py-1">
        <div className="flex items-center space-x-2">
          <div className="flex min-w-[50px] items-center justify-center rounded-md border bg-muted px-2 py-1">
            <span className="text-xs font-medium text-muted-foreground">
              {selectedCell
                ? `${getColumnLabel(selectedCell.col)}${selectedCell.row + 1}`
                : 'A1'}
            </span>
          </div>
          <div className="flex flex-1 items-center space-x-2">
            <div className="flex items-center text-muted-foreground">
              <svg
                className="h-3.5 w-3.5"
                fill="none"
                stroke="currentColor"
                viewBox="0 0 24 24"
              >
                <path
                  strokeLinecap="round"
                  strokeLinejoin="round"
                  strokeWidth={2}
                  d="M9 7h6m0 10v-3m-3 3h.01M9 17h.01M9 14h.01M12 14h.01M15 11h.01M12 11h.01M9 11h.01M7 21h10a2 2 0 002-2V5a2 2 0 00-2-2H7a2 2 0 00-2 2v14a2 2 0 002 2z"
                />
              </svg>
            </div>
            <input
              ref={formulaBarRef}
              type="text"
              className={`flex-1 rounded-md border border-input bg-background px-2 py-1 text-sm ring-offset-background transition-colors file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 ${
                isEditing ? 'ring-2 ring-ring ring-offset-2' : ''
              } ${isCalculating ? 'animate-pulse' : ''}`}
              placeholder="Введите формулу или значение..."
              value={formulaBarValue}
              onChange={(e) => onValueChange(e.target.value)}
              onFocus={onFocus}
              onBlur={onBlur}
              onKeyDown={onKeyDown}
            />
            {isCalculating && (
              <div className="flex items-center text-muted-foreground">
                <svg
                  className="h-3.5 w-3.5 animate-spin"
                  fill="none"
                  viewBox="0 0 24 24"
                >
                  <circle
                    className="opacity-25"
                    cx="12"
                    cy="12"
                    r="10"
                    stroke="currentColor"
                    strokeWidth="4"
                  ></circle>
                  <path
                    className="opacity-75"
                    fill="currentColor"
                    d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"
                  ></path>
                </svg>
              </div>
            )}
          </div>
        </div>
      </div>
    )
  },
)

// --- Main Component ---
const DualSpreadsheet: FC<DualSpreadsheetProps> = ({ templateData = {} }) => {
  const { revision, ...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 || {},
  })

  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 [columnWidths, setColumnWidths] = useState<Record<SheetType, number[]>>(
    () => ({
      report: Array(COL_COUNT).fill(96),
      calculations: Array(COL_COUNT).fill(96),
    }),
  )

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

  // Загрузка данных шаблона один раз при инициализации
  useEffect(() => {
    const reportTemplate = templateData?.[SHEET_NAMES.report]
    if (reportTemplate) {
      Object.entries(reportTemplate).forEach(([cellName, value]) => {
        initialTemplateValues.current[cellName] = String(value)
      })
    }
  }, [templateData])

  // --- Синхронизация UI ---

  // Синхронизация строки формул
  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) {
      if (activeCellInputRef.current) {
        activeCellInputRef.current.focus()
        activeCellInputRef.current.select()
      }
    }
  }, [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]
        multiSheetEngine.setCellValueWithoutRecalc(
          sheetName,
          selectedCell.row,
          selectedCell.col,
          editingValue,
        )
        multiSheetEngine.debouncedRecalc()
      }
      setIsEditing(false)
      setEditingValue('') // Очищаем временное значение
      containerRefs.current[activeSheet]?.focus({ preventScroll: true })
    },
    [activeSheet, selectedCell, editingValue, multiSheetEngine],
  )

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

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

  const moveSelection = useCallback(
    (deltaRow: number, deltaCol: number) => {
      if (!selectedCell) {
        // Если ничего не выбрано, выбираем A1
        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) {
        // Логика внутри Cell компонента
        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)
        }),
      )
    },
    [],
  )

  // --- Formula Bar Specific Handlers ---
  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(() => {
    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],
  )

  // --- Render Functions ---
  const renderSpreadsheet = (sheetType: SheetType) => {
    const widths = columnWidths[sheetType]
    const sheetName = SHEET_NAMES[sheetType]

    return (
      <div
        ref={(el) => (containerRefs.current[sheetType] = el)}
        className="flex h-full flex-col overflow-hidden rounded-lg border bg-card shadow-sm"
        onKeyDown={handleKeyDown}
        tabIndex={0}
      >
        <div className="flex-shrink-0 border-b bg-muted/50 px-3 py-1">
          <div className="flex items-center space-x-2">
            <div
              className={`h-2 w-2 rounded-full ${
                sheetType === 'report' ? 'bg-primary' : 'bg-emerald-500'
              }`}
            ></div>
            <h3 className="text-xs font-medium text-muted-foreground">
              {sheetType === 'report' ? 'Отчет' : 'Расчеты'}
            </h3>
          </div>
        </div>
        <div className="flex-1 overflow-auto">
          <table
            className="w-full border-collapse"
            style={{ tableLayout: 'fixed' }}
          >
            <thead>
              <tr>
                <th className="h-7 w-10 border border-border bg-muted text-xs font-medium text-muted-foreground"></th>
                {Array.from({ length: COL_COUNT }, (_, i) => {
                  const handleMouseDown = (e: React.MouseEvent) => {
                    e.preventDefault()
                    const startX = e.clientX
                    const startWidth = widths[i]

                    const handleMouseMove = (me: MouseEvent) => {
                      const newWidth = startWidth + (me.clientX - startX)
                      handleColumnResize(sheetType, i, newWidth)
                    }

                    const handleMouseUp = () => {
                      document.removeEventListener('mousemove', handleMouseMove)
                      document.removeEventListener('mouseup', handleMouseUp)
                    }

                    document.addEventListener('mousemove', handleMouseMove)
                    document.addEventListener('mouseup', handleMouseUp)
                  }
                  return (
                    <th
                      key={i}
                      className="relative h-7 border border-border bg-muted text-center text-xs font-medium text-muted-foreground"
                      style={{ width: widths[i] }}
                    >
                      {getColumnLabel(i)}
                      <div
                        className="absolute right-0 top-0 h-full w-1 cursor-col-resize hover:bg-primary hover:bg-opacity-50"
                        onMouseDown={handleMouseDown}
                      />
                    </th>
                  )
                })}
              </tr>
            </thead>
            <tbody>
              {Array.from({ length: ROW_COUNT }).map((_, rowIndex) => (
                <tr key={rowIndex}>
                  <td className="h-7 w-10 border border-border bg-muted text-center text-xs font-medium text-muted-foreground">
                    {rowIndex + 1}
                  </td>
                  {Array.from({ length: COL_COUNT }).map((_, colIndex) => {
                    const isCellSelected =
                      selectedCell?.row === rowIndex &&
                      selectedCell?.col === colIndex &&
                      activeSheet === sheetType
                    const isCellEditing = isCellSelected && isEditing

                    const rawValue = isCellEditing
                      ? editingValue
                      : multiSheetEngine.getCellRawValue(
                          sheetName,
                          rowIndex,
                          colIndex,
                        )
                    const displayValue = isCellEditing
                      ? '' // Не показывать вычисленное значение во время редактирования
                      : String(
                          multiSheetEngine.getCellValue(
                            sheetName,
                            rowIndex,
                            colIndex,
                          ) || '',
                        )

                    const cellName = getColumnLabel(colIndex) + (rowIndex + 1)
                    const templateValue =
                      initialTemplateValues.current[cellName] ?? ''
                    const isModified =
                      sheetType === 'report' &&
                      templateValue !== '' &&
                      rawValue !== templateValue

                    return (
                      <Cell
                        key={colIndex}
                        sheetType={sheetType}
                        rowIndex={rowIndex}
                        colIndex={colIndex}
                        columnWidth={widths[colIndex]}
                        isSelected={isCellSelected}
                        isEditing={isCellEditing}
                        displayValue={displayValue}
                        rawValue={rawValue}
                        isModified={isModified}
                        onCellClick={handleCellClick}
                        onCellDoubleClick={handleCellDoubleClick}
                        onCellValueChange={handleCellChange}
                        stopEditing={stopEditing}
                        setActiveSheet={setActiveSheet}
                        activeCellRef={activeCellInputRef}
                      />
                    )
                  })}
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      </div>
    )
  }

  // Используем revision в качестве зависимости, чтобы гарантировать перерисовку
  // при изменении данных в движке.
  const memoizedReportSheet = useMemo(
    () => renderSpreadsheet('report'),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [
      columnWidths.report,
      activeSheet,
      selectedCell,
      isEditing,
      editingValue,
      revision,
    ],
  )

  const memoizedCalculationsSheet = useMemo(
    () => renderSpreadsheet('calculations'),
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [
      columnWidths.calculations,
      activeSheet,
      selectedCell,
      isEditing,
      editingValue,
      revision,
    ],
  )

  return (
    <div className="flex h-screen flex-col bg-background">
      <div className="flex-shrink-0">
        <FormulaBar
          sheetType={activeSheet}
          activeSheet={activeSheet}
          selectedCell={selectedCell}
          formulaBarValue={formulaBarValue}
          isCalculating={multiSheetEngine.isCalculating}
          isEditing={isEditing}
          onValueChange={handleFormulaBarChange}
          onFocus={handleFormulaBarFocus}
          onBlur={handleFormulaBarBlur}
          onKeyDown={handleFormulaBarKeyDown}
          formulaBarRef={(el) => (formulaBarRefs.current[activeSheet] = el)}
        />
      </div>
      {/* Двойная панель */}
      <div className="flex flex-1 gap-1 overflow-hidden p-1">
        <div className="min-w-0 flex-1">{memoizedReportSheet}</div>
        <div className="min-w-0 flex-1">{memoizedCalculationsSheet}</div>
      </div>
    </div>
  )
}

export default DualSpreadsheet
