import DualSpreadsheet from '@/component/DualSpreadsheet/DualSpreadsheet'
import { Button } from '@/component/ui/button'
import { getElementDefinition } from '@/entitiy/element/model/interface'
import { useTemplateContext } from '@/entitiy/template/model/TemplateContext'
import { cellAddressToCoordinates } from '@/lib/cell-utils'
import { useToast } from '@/lib/hooks/useToast'
import { getLatestFileForTemplate } from '@/service/fileApiService'
import { Template, TemplateElement } from '@/type/template'
import { ArrowLeft, FileText, Grid, Save, Settings, Wrench } from 'lucide-react'
import { FC, useEffect, useMemo, useRef, useState } from 'react'
import { useNavigate, useParams } from 'react-router-dom'

interface ProtocolFormProps {
  template: Template
  onSave: (data: Record<string, any>) => void
  onBack: () => void
}

interface FormElementProps {
  element: TemplateElement
  value: any
  onChange: (value: any) => void
}

const FormElement: FC<FormElementProps> = ({ element, value, onChange }) => {
  // Получаем определение элемента из реестра
  const elementDefinition = getElementDefinition(element.type)

  // Если определение элемента не найдено, показываем ошибку
  if (!elementDefinition) {
    return (
      <div className="rounded-md border border-red-200 bg-red-50 p-3 text-sm text-red-700">
        Элемент типа "{element.type}" не найден в реестре
      </div>
    )
  }

  const renderElement = () => (
    <elementDefinition.Render
      config={element as any}
      value={value}
      onChange={onChange}
    />
  )

  return (
    <div className="relative space-y-3">
      {/* Показываем индикатор ячеек для всех элементов */}
      {element.targetCells && element.targetCells.length > 0 && (
        <div className="group/cells absolute right-0 top-0">
          <Grid className="h-3 w-3 cursor-help text-gray-500 opacity-60 transition-opacity hover:opacity-100" />
          <div className="pointer-events-none absolute right-0 top-full z-50 mt-2 whitespace-nowrap rounded bg-gray-900 p-2 text-xs text-white opacity-0 shadow-lg transition-opacity group-hover/cells:opacity-100">
            <div className="mb-1 font-medium">Целевые ячейки:</div>
            {element.targetCells.map((cell, i) => (
              <div key={i} className="font-mono">
                {cell.sheet}!{cell.cell}
                {cell.displayName && (
                  <span className="ml-1 text-gray-300">
                    ({cell.displayName})
                  </span>
                )}
              </div>
            ))}
          </div>
        </div>
      )}

      {/* Рендер элемента через единый интерфейс */}
      {renderElement()}
    </div>
  )
}

const ProtocolForm: FC<ProtocolFormProps> = ({ template, onSave, onBack }) => {
  const [formData, setFormData] = useState<Record<string, any>>({})
  const [showSpreadsheet, setShowSpreadsheet] = useState(false)
  const [isInitialized, setIsInitialized] = useState(false)
  const engineRef = useRef<any>(null)
  const toast = useToast()
  const navigate = useNavigate()

  // Инициализация значений для специальных элементов
  useEffect(() => {
    if (!isInitialized && template.elements.length > 0) {
      const initialData: Record<string, any> = {}

      template.elements.forEach(element => {
        // Получаем определение элемента
        const elementDefinition = getElementDefinition(element.type)
        if (elementDefinition?.getInitialValue) {
          // Используем метод getInitialValue для получения начального значения
          const initialValue = elementDefinition.getInitialValue(element as any)
          if (initialValue !== undefined) {
            initialData[element.id] = initialValue
          }
        }
      })

      if (Object.keys(initialData).length > 0) {
        setFormData(initialData)
      }

      setIsInitialized(true)
    }
  }, [template.elements, isInitialized])

  const handleFieldChange = (elementId: string, value: any) => {
    setFormData(prev => ({
      ...prev,
      [elementId]: value,
    }))

    // Прямо обновляем движок, чтобы формулы пересчитались
    if (engineRef.current) {
      const element = template.elements.find(el => el.id === elementId)
      if (element) {
        // Получаем определение элемента
        const elementDefinition = getElementDefinition(element.type)
        if (elementDefinition) {
          // Используем единый интерфейс для получения пар ячейка-значение
          const cellValues = elementDefinition.mapToCellValues(
            element as any,
            value
          )

          // Записываем все значения в соответствующие ячейки
          cellValues.forEach(({ target, value: cellValue }) => {
            const { row, col } = cellAddressToCoordinates(target.cell)
            engineRef.current.setCellValueWithoutRecalc(
              target.sheet,
              row,
              col,
              cellValue
            )
          })

          engineRef.current.debouncedRecalc()
        }
      }
    }
  }

  const handleSave = async () => {
    // Ищем элемент с названием протокола (должен иметь специальный тип или название)
    const protocolNameElement = template.elements.find(
      el => el.name === 'protocolName' || el.label === 'Название протокола'
    )
    const protocolName = protocolNameElement
      ? formData[protocolNameElement.id]
      : 'Новый протокол'

    const data = {
      protocolName,
      templateId: template.id,
      formData,
      createdAt: new Date(),
    }
    onSave(data)

    try {
      if (!engineRef.current) {
        toast.error('Движок ещё не инициализирован')
        return
      }

      // 1. Записываем ВСЕ значения формы в движок (поверх текущих)
      template.elements.forEach(el => {
        let value = formData[el.id]
        if (value === undefined || value === null) value = ''

        // Получаем определение элемента
        const elementDefinition = getElementDefinition(el.type)
        if (elementDefinition) {
          // Используем единый интерфейс для получения пар ячейка-значение
          const cellValues = elementDefinition.mapToCellValues(el as any, value)

          // Записываем все значения в соответствующие ячейки
          cellValues.forEach(({ target, value: cellValue }) => {
            const { row, col } = cellAddressToCoordinates(target.cell)
            if (target.sheet === 'Calculations') {
              toast.warning('Обнаружен лист Calculations')
            }
            const sheetName =
              target.sheet === 'R' || target.sheet === 'Calculations'
                ? 'R'
                : 'L'
            engineRef.current.setCellValueWithoutRecalc(
              sheetName,
              row,
              col,
              cellValue
            )
          })
        }
      })

      // 2. Пересчитываем формулы
      engineRef.current.recalculate()

      // 3. Получаем изменения только левого листа относительно базового файла
      const allModified = engineRef.current?.getAllModifiedCells() || {}
      // Преобразуем в конечные (вычисленные) значения
      const cellsToUpdate: Record<string, any> = {}
      const modifiedLeft = allModified['L'] || {}
      Object.keys(modifiedLeft).forEach(cellAddress => {
        const { row, col } = cellAddressToCoordinates(cellAddress)
        cellsToUpdate[cellAddress] = engineRef.current.getCellValue(
          'L',
          row,
          col
        )
      })

      // Получаем последний файл для шаблона
      const latestFile = await getLatestFileForTemplate(template.id)
      if (!latestFile) {
        toast.error('Не найден исходный файл Excel для шаблона')
        return
      }

      const body = {
        cells_to_update: cellsToUpdate,
        file_id: latestFile.id,
        template_id: template.id,
      }

      const resp = await fetch('/api/protocols/', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(body),
      })

      if (!resp.ok) throw new Error(`HTTP ${resp.status}`)

      // Получаем файл как blob и скачиваем его
      const blob = await resp.blob()
      const url = window.URL.createObjectURL(blob)
      const a = document.createElement('a')
      a.href = url

      // Получаем значение из ячейки R!A1 для имени файла
      const filenameFromCell = engineRef.current.getCellValue('R', 0, 0) // R!A1
      console.log(filenameFromCell)
      let filename = 'Измените R!A1.xlsx'

      if (
        filenameFromCell &&
        typeof filenameFromCell === 'string' &&
        filenameFromCell.trim()
      ) {
        // Очищаем имя файла от недопустимых символов
        const cleanName = filenameFromCell.trim().replace(/[<>:"/\\|?*]/g, '_')
        filename = `${cleanName}.xlsx`
      }

      // Если сервер передал имя файла в заголовке Content-Disposition, игнорируем его
      // и используем строго значение из R!A1
      const contentDisposition = resp.headers.get('content-disposition')
      if (contentDisposition) {
        // Оставляем возможность переопределения только если R!A1 пуста
        if (!filenameFromCell || !filenameFromCell.toString().trim()) {
          const matches = contentDisposition.match(
            /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/
          )
          if (matches && matches[1]) {
            filename = matches[1].replace(/['"]/g, '')
          }
        }
      }

      a.download = filename
      document.body.appendChild(a)
      a.click()
      window.URL.revokeObjectURL(url)
      document.body.removeChild(a)

      toast.success('Протокол создан и загружен!')
    } catch (err) {
      console.error('Ошибка при создании протокола', err)
      toast.error('Ошибка при создании протокола')
    }
  }

  const canvasSize = useMemo(() => {
    const PADDING_Y = 200
    const baseWidth = 1200
    const baseHeight = 800

    if (template.elements.length === 0) {
      return { width: baseWidth, height: baseHeight }
    }

    const contentHeight = Math.max(
      0,
      ...template.elements.map(
        el => (el.layout?.y || 0) + (el.layout?.height || 0)
      )
    )

    return {
      width: baseWidth,
      height: Math.max(baseHeight, contentHeight + PADDING_Y),
    }
  }, [template.elements])

  const canSave = true

  return (
    <div className="flex h-screen flex-col bg-background">
      <div className="flex-shrink-0 bg-card px-4 py-2">
        <div className="relative flex items-center">
          {/* Левая часть: кнопка назад и заголовок */}
          <div className="flex items-center gap-2">
            <Button variant="ghost" size="icon" onClick={onBack}>
              <ArrowLeft className="h-4 w-4" />
            </Button>
            <div className="flex items-center space-x-2">
              <FileText className="h-5 w-5" />
              <h1 className="text-lg font-semibold">Создание протокола</h1>
              <span className="text-sm text-muted-foreground">—</span>
              <span className="text-sm text-muted-foreground">
                {template.name}
              </span>
            </div>
          </div>
          {/* Центрированные кнопки */}
          <div className="absolute left-1/2 top-1/2 flex -translate-x-1/2 -translate-y-1/2 gap-2">
            <Button
              variant={showSpreadsheet ? 'default' : 'outline'}
              size="icon"
              onClick={() => setShowSpreadsheet(!showSpreadsheet)}
              aria-label={
                showSpreadsheet ? 'Скрыть таблицы' : 'Показать таблицы'
              }
            >
              <Grid className="h-4 w-4" />
            </Button>
            <Button variant="outline" onClick={handleSave} disabled={!canSave}>
              <Save className="h-4 w-4" />
              Сохранить протокол
            </Button>
          </div>
          {/* Кнопки справа */}
          <div className="absolute right-0 flex gap-2">
            <Button
              variant="link"
              size="sm"
              onClick={() => navigate(`/templates/${template.id}/edit`)}
              className="flex items-center gap-1 hover:bg-muted"
            >
              <Settings className="h-4 w-4" />
              <span className="text-sm">Редактор шаблона</span>
            </Button>
            <Button
              variant="link"
              size="sm"
              onClick={() => navigate(`/templates/${template.id}/elements`)}
              className="flex items-center gap-1 hover:bg-muted"
            >
              <Wrench className="h-4 w-4" />
              <span className="text-sm">Редактор интерфейса</span>
            </Button>
          </div>
        </div>
      </div>

      {/* Основное содержимое */}
      <div className="flex-1 overflow-hidden">
        <div className={`${showSpreadsheet ? 'block' : 'hidden'} h-full`}>
          <DualSpreadsheet
            templateData={template.excelData ? { L: template.excelData } : {}}
            mergedCells={template.mergedCells || []}
            templateId={template.id}
            onEngineReady={engine => {
              engineRef.current = engine
            }}
            enableAutoSave={false}
          />
        </div>

        {/* Форма */}
        <div
          className={`${showSpreadsheet ? 'hidden' : 'block'} h-full overflow-auto`}
        >
          <div
            className="relative mx-auto my-8"
            style={{ width: canvasSize.width, height: canvasSize.height }}
          >
            {template.elements.map(element => {
              const layout = element.layout || {
                x: 50,
                y: 50,
                width: 300,
                height: 80,
              }
              return (
                <div
                  key={element.id}
                  className="absolute"
                  style={{
                    left: layout.x,
                    top: layout.y,
                    width: layout.width,
                    minHeight: layout.height,
                    zIndex: layout.zIndex || 1,
                  }}
                >
                  <FormElement
                    element={element}
                    value={formData[element.id]}
                    onChange={value => handleFieldChange(element.id, value)}
                  />
                </div>
              )
            })}

            {template.elements.length === 0 && (
              <div className="absolute inset-0 flex items-center justify-center">
                <div className="text-center text-gray-400">
                  <FileText className="mx-auto mb-4 h-16 w-16" />
                  <h3 className="mb-2 text-lg font-medium text-gray-900">
                    Нет элементов формы
                  </h3>
                  <p className="mb-4 text-gray-600">
                    В этом шаблоне пока не созданы элементы формы
                  </p>
                  <Button
                    variant="outline"
                    onClick={() => window.history.back()}
                  >
                    Настроить шаблон
                  </Button>
                </div>
              </div>
            )}
          </div>
        </div>
      </div>
    </div>
  )
}

export const ProtocolCreation: FC = () => {
  const navigate = useNavigate()
  const { templateId } = useParams<{ templateId?: string }>()
  const { templates } = useTemplateContext()
  const [selectedTemplate, setSelectedTemplate] = useState<Template | null>(
    null
  )
  const toast = useToast()
  // Автоматически выбираем шаблон если передан ID в URL
  useEffect(() => {
    if (templateId && templates.length > 0) {
      const template = templates.find(t => t.id === templateId)
      if (template) {
        setSelectedTemplate(template)
      }
    }
  }, [templateId, templates])

  const handleProtocolSave = (data: Record<string, any>) => {
    toast.success(`Протокол "${data.protocolName}" сохранен!`)
  }

  const handleBack = () => {
    navigate('/templates')
  }

  if (!selectedTemplate) {
    return (
      <div className="flex h-screen items-center justify-center">
        <div className="text-center">
          <FileText className="mx-auto mb-4 h-16 w-16 text-gray-400" />
          <h3 className="mb-2 text-lg font-medium text-gray-900">
            Шаблон не найден
          </h3>
          <p className="mb-4 text-gray-600">
            Перейдите к списку шаблонов для выбора
          </p>
          <Button onClick={() => navigate('/templates')}>
            К списку шаблонов
          </Button>
        </div>
      </div>
    )
  }

  return (
    <ProtocolForm
      template={selectedTemplate}
      onSave={handleProtocolSave}
      onBack={handleBack}
    />
  )
}
