import { getElementDefinition } from '@/entity/element/model/interface'
import {
  ElementLayout,
  FormLayoutSettings,
  TemplateElement,
} from '@/type/template'
import { Edit, Grid, Move, Trash2 } from 'lucide-react'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { Rnd } from 'react-rnd'
import { Button } from 'shared/ui/button'

// Минимальные размеры для разных типов элементов.
// Если понадобится скорректировать размеры для конкретного элемента,
// достаточно изменить эту таблицу.
const ELEMENT_MIN_SIZE: Record<string, { width: number; height: number }> = {
  text: { width: 120, height: 80 },
  textarea: { width: 160, height: 80 },
  number: { width: 120, height: 40 },
  date: { width: 140, height: 40 },
  select: { width: 140, height: 40 },
  radio: { width: 160, height: 80 },
  checkbox: { width: 140, height: 40 },
  standards: { width: 200, height: 50 },
  calibration_conditions: { width: 350, height: 50 },
  button_group: { width: 180, height: 80 },
}

interface DraggableElementProps {
  element: TemplateElement
  isSelected: boolean
  onSelect: () => void
  onUpdate: (layout: ElementLayout) => void
  onDelete: () => void
  onEdit?: () => void
  gridSize: number
  layoutSettings: FormLayoutSettings
}

const DraggableElement: React.FC<DraggableElementProps> = React.memo(
  ({
    element,
    isSelected,
    onSelect,
    onUpdate,
    onDelete,
    onEdit,
    gridSize,
    layoutSettings,
  }) => {
    const layout = element.layout || {
      x: 50,
      y: 50,
      width: 300,
      height: 80,
      zIndex: 1,
    }

    const handleDragStop = useCallback(
      (_e: any, d: { x: number; y: number }) => {
        // Вызываем onUpdate только если позиция действительно изменилась,
        // чтобы избежать ложных срабатываний при клике.
        if (d.x !== layout.x || d.y !== layout.y) {
          onUpdate({ ...layout, x: d.x, y: d.y })
        }
      },
      [layout, onUpdate]
    )

    const handleResizeStop = useCallback(
      (
        _e: any,
        _dir: any,
        ref: HTMLElement,
        _delta: any,
        pos: { x: number; y: number }
      ) => {
        onUpdate({
          ...layout,
          width: parseInt(ref.style.width, 10),
          height: parseInt(ref.style.height, 10),
          x: pos.x,
          y: pos.y,
        })
      },
      [layout, onUpdate]
    )

    const handleDeleteClick = useCallback(
      (e: React.MouseEvent) => {
        e.stopPropagation()
        onDelete()
      },
      [onDelete]
    )

    const handleEditClick = useCallback(
      (e: React.MouseEvent) => {
        e.stopPropagation()
        onEdit?.()
      },
      [onEdit]
    )

    /*
     * Render a lightweight, disabled preview of the element so that the user can
     * see how the real control looks directly on the canvas instead of a plain
     * colored square. Keeping the elements disabled and wrapped with
     * `pointer-events-none` guarantees that they do not interfere with the drag
     * behaviour of Rnd and keeps rendering costs minimal.
     */
    const previewControl = useMemo(() => {
      const elementDefinition = getElementDefinition(element.type)
      if (!elementDefinition || !elementDefinition.Preview) {
        console.error(`Element definition for ${element.type} not found`)
        return null
      }
      return (
        <div className="pointer-events-none w-full">
          <elementDefinition.Preview config={element as any} />
        </div>
      )
    }, [element])

    return (
      <Rnd
        dragGrid={layoutSettings.snapToGrid ? [gridSize, gridSize] : [1, 1]}
        resizeGrid={layoutSettings.snapToGrid ? [gridSize, gridSize] : [1, 1]}
        default={{
          x: layout.x,
          y: layout.y,
          width: layout.width,
          height: layout.height,
        }}
        onDragStop={handleDragStop}
        onResizeStop={handleResizeStop}
        minWidth={ELEMENT_MIN_SIZE[element.type]?.width ?? 120}
        minHeight={ELEMENT_MIN_SIZE[element.type]?.height ?? 32}
        bounds="parent"
        className={`group ${isSelected ? 'z-20 ring-2 ring-blue-500' : 'z-10'}`}
        onClick={onSelect}
      >
        <div
          className={`h-full cursor-move ${
            isSelected
              ? 'rounded-md bg-blue-50/10 p-1'
              : 'rounded-md p-1 hover:bg-gray-50/10'
          }`}
        >
          {/* Controls (only visible when selected or hovered) */}
          <div
            className={`absolute right-1 top-1 flex items-center gap-0.5 ${
              isSelected ? 'opacity-100' : 'opacity-0 group-hover:opacity-60'
            }`}
          >
            {/* Индикатор ячеек */}
            {element.targetCells && element.targetCells.length > 0 && (
              <div className="group/cells relative">
                <div className="flex !h-5 !w-5 cursor-help items-center justify-center rounded hover:bg-gray-100">
                  <Grid className="!h-3 !w-3 text-gray-500" />
                </div>
                <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>
            )}
            {onEdit && (
              <Button
                variant="ghost"
                size="icon"
                className="!h-5 !w-5 !min-w-0 cursor-pointer !p-0 hover:bg-blue-100"
                onClick={handleEditClick}
              >
                <Edit className="!h-3 !w-3 text-blue-600" />
              </Button>
            )}
            <Button
              variant="ghost"
              size="icon"
              className="!h-5 !w-5 !min-w-0 cursor-pointer !p-0 hover:bg-red-100"
              onClick={handleDeleteClick}
            >
              <Trash2 className="!h-3 !w-3 text-red-600" />
            </Button>
          </div>

          {/* Real element preview */}
          {previewControl && (
            <div className="flex-1 space-y-1">{previewControl}</div>
          )}

          {/* Additional info (only visible on selection to preserve visual clarity & perf) */}
          {isSelected && (
            <div className="mt-1 space-y-1 text-xs opacity-75">
              {/* Здесь можно добавить дополнительную информацию при необходимости */}
            </div>
          )}
        </div>
      </Rnd>
    )
  }
)

interface VisualLayoutEditorProps {
  elements: TemplateElement[]
  layoutSettings: FormLayoutSettings
  onElementUpdate: (
    elementId: string,
    updates: Partial<TemplateElement>
  ) => void
  onElementDelete: (elementId: string) => void
  onLayoutSettingsChange: (settings: FormLayoutSettings) => void
  onElementEdit?: (element: TemplateElement) => void
  onElementAdd?: (element: Omit<TemplateElement, 'id'>) => void
  isDialogOpen?: boolean // Добавляем новый проп
}

export const VisualLayoutEditor: React.FC<VisualLayoutEditorProps> = ({
  elements,
  layoutSettings,
  onElementUpdate,
  onElementDelete,
  onLayoutSettingsChange,
  onElementEdit,
  onElementAdd,
  isDialogOpen = false, // Значение по умолчанию
}) => {
  // console.log('VisualLayoutEditor render with elements:', elements)
  const [selectedElementId, setSelectedElementId] = useState<string | null>(
    null
  )
  const [copiedElement, setCopiedElement] = useState<TemplateElement | null>(
    null
  )

  // Обработчик клавиш для копирования/вставки
  useEffect(() => {
    // Отключаем обработчики если открыт диалог
    if (isDialogOpen) {
      return
    }

    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.ctrlKey || e.metaKey) {
        if (e.key === 'c' && selectedElementId) {
          e.preventDefault()
          const elementToCopy = elements.find(el => el.id === selectedElementId)
          if (elementToCopy) {
            setCopiedElement(elementToCopy)
          }
        } else if (e.key === 'v' && copiedElement && onElementAdd) {
          e.preventDefault()
          const newElement = {
            ...copiedElement,
            layout: {
              ...copiedElement.layout,
              x: (copiedElement.layout?.x || 0) + 20,
              y: (copiedElement.layout?.y || 0) + 20,
              width: copiedElement.layout?.width || 300,
              height: copiedElement.layout?.height || 80,
            },
          }
          delete (newElement as any).id // Удаляем id чтобы создался новый
          onElementAdd(newElement)
        }
      }
    }

    document.addEventListener('keydown', handleKeyDown)
    return () => document.removeEventListener('keydown', handleKeyDown)
  }, [selectedElementId, elements, copiedElement, onElementAdd, isDialogOpen])

  const canvasSize = useMemo(() => {
    const PADDING_Y = 200

    const baseWidth = 1200
    const baseHeight = 800

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

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

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

  const GridPattern = useMemo(() => {
    if (!layoutSettings.showGrid) return null
    const gridSize = layoutSettings.gridSize
    return (
      <div
        className="pointer-events-none absolute inset-0"
        style={{
          backgroundImage: `radial-gradient(circle, #e5e7eb 1px, transparent 1px)`,
          backgroundSize: `${gridSize}px ${gridSize}px`,
        }}
      />
    )
  }, [layoutSettings.showGrid, layoutSettings.gridSize])

  const handleElementUpdateCallback = useCallback(
    (elementId: string, layout: ElementLayout) => {
      onElementUpdate(elementId, { layout })
    },
    [onElementUpdate]
  )

  const handleCanvasClick = useCallback(
    (e: React.MouseEvent<HTMLDivElement>) => {
      // Снимаем выделение при клике по пустому месту
      if (e.target === e.currentTarget) {
        setSelectedElementId(null)
      }
    },
    []
  )

  const toggleGrid = useCallback(() => {
    onLayoutSettingsChange({
      ...layoutSettings,
      showGrid: !layoutSettings.showGrid,
    })
  }, [layoutSettings, onLayoutSettingsChange])

  return (
    <div className="flex h-full flex-col bg-background">
      <div
        className="relative flex-1 overflow-auto"
        onClick={handleCanvasClick}
      >
        <div
          className="relative mx-auto my-8 select-none border border-gray-300 bg-white"
          style={{ width: canvasSize.width, height: canvasSize.height }}
          onClick={handleCanvasClick}
        >
          {GridPattern}
          {elements.map(element => (
            <DraggableElement
              key={element.id}
              element={element}
              isSelected={selectedElementId === element.id}
              onSelect={() => setSelectedElementId(element.id)}
              onUpdate={layout =>
                handleElementUpdateCallback(element.id, layout)
              }
              onDelete={() => onElementDelete(element.id)}
              onEdit={onElementEdit ? () => onElementEdit(element) : undefined}
              gridSize={layoutSettings.gridSize}
              layoutSettings={layoutSettings}
            />
          ))}
          {elements.length === 0 && (
            <div className="pointer-events-none absolute inset-0 flex items-center justify-center">
              <div className="text-center text-gray-400">
                <Move className="mx-auto mb-4 h-16 w-16" />
                <p className="mb-2 text-xl font-medium">Холст пуст</p>
                <p className="text-sm">Добавьте свой первый элемент</p>
              </div>
            </div>
          )}
        </div>
      </div>
    </div>
  )
}
