'use client'

import { useState, useEffect, useCallback, useRef } from 'react'
import { DndContext, DragEndEvent, DragOverlay, DragStartEvent, useDroppable, MouseSensor, TouchSensor, useSensor, useSensors } from '@dnd-kit/core'
import { Plus, Save, Loader2, Trash2, Edit3, X, Check } from 'lucide-react'
import toast from 'react-hot-toast'
import FloorPlanTable from './FloorPlanTable'
import UnplacedTablesSidebar from './UnplacedTablesSidebar'

interface TableData {
  id: string
  number: number
  name?: string | null
  capacity: number
  shape: string
  floorAreaId?: string | null
  posX?: number | null
  posY?: number | null
}

interface FloorArea {
  id: string
  name: string
  sortOrder: number
  _count?: { tables: number }
}

interface FloorPlanEditorProps {
  tables: TableData[]
  storeId: string
  onRefresh: () => void
}

function CanvasDroppable({ children, canvasRef }: { children: React.ReactNode; canvasRef: React.RefObject<HTMLDivElement | null> }) {
  const { setNodeRef, isOver } = useDroppable({ id: 'floor-canvas' })

  // Merge droppable ref with canvasRef so position calculations use the same element
  const mergedRef = useCallback((node: HTMLDivElement | null) => {
    setNodeRef(node)
    ;(canvasRef as React.MutableRefObject<HTMLDivElement | null>).current = node
  }, [setNodeRef, canvasRef])

  return (
    <div
      ref={mergedRef}
      className={`
        flex-1 relative overflow-hidden h-full
        bg-white dark:bg-gray-900
        ${isOver ? 'ring-2 ring-orange-400 ring-inset' : ''}
      `}
      style={{
        backgroundImage: `
          linear-gradient(to right, rgba(156,163,175,0.15) 1px, transparent 1px),
          linear-gradient(to bottom, rgba(156,163,175,0.15) 1px, transparent 1px)
        `,
        backgroundSize: '40px 40px',
      }}
    >
      {children}
    </div>
  )
}

export default function FloorPlanEditor({ tables, storeId, onRefresh }: FloorPlanEditorProps) {
  const [floorAreas, setFloorAreas] = useState<FloorArea[]>([])
  const [activeFloorId, setActiveFloorId] = useState<string>('')
  const [localPositions, setLocalPositions] = useState<Record<string, { posX: number; posY: number; floorAreaId?: string | null }>>({})
  const [selectedTableId, setSelectedTableId] = useState<string | null>(null)
  const [isDirty, setIsDirty] = useState(false)
  const [saving, setSaving] = useState(false)
  const [loadingAreas, setLoadingAreas] = useState(true)

  // Room management state
  const [showAddRoom, setShowAddRoom] = useState(false)
  const [newRoomName, setNewRoomName] = useState('')
  const [addingRoom, setAddingRoom] = useState(false)
  const [editingRoomId, setEditingRoomId] = useState<string | null>(null)
  const [editRoomName, setEditRoomName] = useState('')

  // Edit table state
  const [editTableName, setEditTableName] = useState('')
  const [editTableCapacity, setEditTableCapacity] = useState('')
  const [editTableShape, setEditTableShape] = useState('rect')

  // Drag overlay state
  const [activeDragId, setActiveDragId] = useState<string | null>(null)

  const canvasRef = useRef<HTMLDivElement>(null)

  // Use MouseSensor + TouchSensor separately so drag doesn't conflict with scroll
  const mouseSensor = useSensor(MouseSensor, {
    activationConstraint: {
      distance: 8, // need to move 8px before drag starts (prevents accidental drag on click)
    },
  })
  const touchSensor = useSensor(TouchSensor, {
    activationConstraint: {
      delay: 200,      // hold for 200ms before drag starts
      tolerance: 5,    // can move 5px during the delay
    },
  })
  const sensors = useSensors(mouseSensor, touchSensor)

  // Fetch floor areas
  const fetchFloorAreas = useCallback(async () => {
    if (!storeId) return
    setLoadingAreas(true)
    try {
      const res = await fetch(`/api/floor-areas?storeId=${storeId}`)
      const data = await res.json()
      const areas = data.floorAreas || []
      setFloorAreas(areas)
      if (areas.length > 0 && !activeFloorId) {
        setActiveFloorId(areas[0].id)
      }
    } catch {
      toast.error('Gagal memuat data ruangan')
    } finally {
      setLoadingAreas(false)
    }
  }, [storeId, activeFloorId])

  useEffect(() => {
    fetchFloorAreas()
  }, [fetchFloorAreas])

  // Initialize local positions from table data
  useEffect(() => {
    const positions: Record<string, { posX: number; posY: number; floorAreaId?: string | null }> = {}
    tables.forEach(t => {
      if (t.posX != null && t.posY != null) {
        positions[t.id] = { posX: t.posX, posY: t.posY, floorAreaId: t.floorAreaId }
      }
    })
    setLocalPositions(positions)
  }, [tables])

  // Tables on current floor
  const tablesOnFloor = tables.filter(t => {
    const pos = localPositions[t.id]
    return pos && pos.floorAreaId === activeFloorId
  })

  // Unplaced tables: no position OR no floorAreaId
  const unplacedTables = tables.filter(t => {
    const pos = localPositions[t.id]
    return !pos || !pos.floorAreaId
  })

  // Selected table data
  const selectedTable = selectedTableId ? tables.find(t => t.id === selectedTableId) : null

  useEffect(() => {
    if (selectedTable) {
      setEditTableName(selectedTable.name || `Meja ${selectedTable.number}`)
      setEditTableCapacity(String(selectedTable.capacity))
      setEditTableShape(selectedTable.shape || 'rect')
    }
  }, [selectedTable])

  const handleDragStart = (event: DragStartEvent) => {
    const data = event.active.data.current as { tableId: string; source: string }
    setActiveDragId(data.tableId)
  }

  const handleDragEnd = (event: DragEndEvent) => {
    setActiveDragId(null)
    const { active, over, delta } = event
    if (!active) return

    const data = active.data.current as { tableId: string; source: string }
    const tableId = data.tableId

    if (data.source === 'sidebar' && over?.id === 'floor-canvas') {
      // Dropped from sidebar to canvas
      const canvas = canvasRef.current
      if (!canvas) return

      const rect = canvas.getBoundingClientRect()
      // Calculate position as percentage based on the mouse position
      // active.rect gives us the element's initial position
      const activeRect = active.rect.current.translated
      if (!activeRect) return

      const centerX = activeRect.left + activeRect.width / 2 - rect.left
      const centerY = activeRect.top + activeRect.height / 2 - rect.top

      const posX = Math.max(0, Math.min(90, (centerX / rect.width) * 100))
      const posY = Math.max(0, Math.min(90, (centerY / rect.height) * 100))

      setLocalPositions(prev => ({
        ...prev,
        [tableId]: { posX, posY, floorAreaId: activeFloorId },
      }))
      setIsDirty(true)
    } else if (data.source === 'canvas') {
      // Moved within canvas
      const canvas = canvasRef.current
      if (!canvas) return

      const rect = canvas.getBoundingClientRect()
      const prev = localPositions[tableId]
      if (!prev) return

      // delta is in pixels, convert to percentage
      const deltaXPercent = (delta.x / rect.width) * 100
      const deltaYPercent = (delta.y / rect.height) * 100

      const newX = Math.max(0, Math.min(90, prev.posX + deltaXPercent))
      const newY = Math.max(0, Math.min(90, prev.posY + deltaYPercent))

      setLocalPositions(prevPos => ({
        ...prevPos,
        [tableId]: { ...prevPos[tableId], posX: newX, posY: newY },
      }))
      setIsDirty(true)
    }
  }

  const handleSave = async () => {
    setSaving(true)
    try {
      const positions = Object.entries(localPositions).map(([id, pos]) => ({
        id,
        posX: pos.posX,
        posY: pos.posY,
        floorAreaId: pos.floorAreaId || null,
      }))

      // Also include tables that were unplaced (need to clear their positions)
      const unplacedIds = tables
        .filter(t => !localPositions[t.id] && (t.posX != null || t.floorAreaId != null))
        .map(t => ({
          id: t.id,
          posX: null as any,
          posY: null as any,
          floorAreaId: null,
        }))

      const allPositions = [...positions, ...unplacedIds]

      if (allPositions.length > 0) {
        const res = await fetch('/api/tables/positions', {
          method: 'PUT',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({ positions: allPositions }),
        })
        if (!res.ok) throw new Error('Failed to save')
      }

      setIsDirty(false)
      toast.success('Layout tersimpan!')
      onRefresh()
    } catch {
      toast.error('Gagal menyimpan layout')
    } finally {
      setSaving(false)
    }
  }

  const handleAddRoom = async () => {
    if (!newRoomName.trim()) return
    setAddingRoom(true)
    try {
      const res = await fetch('/api/floor-areas', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ storeId, name: newRoomName.trim() }),
      })
      if (!res.ok) throw new Error((await res.json()).error)
      const data = await res.json()
      toast.success(`Ruangan "${data.floorArea.name}" dibuat`)
      setNewRoomName('')
      setShowAddRoom(false)
      await fetchFloorAreas()
      setActiveFloorId(data.floorArea.id)
    } catch (err: any) {
      toast.error(err.message)
    } finally {
      setAddingRoom(false)
    }
  }

  const handleRenameRoom = async (id: string) => {
    if (!editRoomName.trim()) return
    try {
      const res = await fetch(`/api/floor-areas/${id}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ name: editRoomName.trim() }),
      })
      if (!res.ok) throw new Error((await res.json()).error)
      toast.success('Nama ruangan diubah')
      setEditingRoomId(null)
      fetchFloorAreas()
    } catch (err: any) {
      toast.error(err.message)
    }
  }

  const handleDeleteRoom = async (id: string) => {
    if (!confirm('Hapus ruangan ini? Meja di dalamnya akan kembali ke "Belum Ditaruh".')) return
    try {
      const res = await fetch(`/api/floor-areas/${id}`, { method: 'DELETE' })
      if (!res.ok) throw new Error((await res.json()).error)
      toast.success('Ruangan dihapus')

      // Clear positions for tables that were in this room
      setLocalPositions(prev => {
        const updated = { ...prev }
        Object.keys(updated).forEach(tableId => {
          if (updated[tableId].floorAreaId === id) {
            delete updated[tableId]
          }
        })
        return updated
      })

      if (activeFloorId === id) {
        const remaining = floorAreas.filter(a => a.id !== id)
        setActiveFloorId(remaining.length > 0 ? remaining[0].id : '')
      }
      fetchFloorAreas()
      onRefresh()
    } catch (err: any) {
      toast.error(err.message)
    }
  }

  const handleUpdateTable = async () => {
    if (!selectedTableId) return
    try {
      const res = await fetch(`/api/tables/${selectedTableId}`, {
        method: 'PUT',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          name: editTableName,
          capacity: parseInt(editTableCapacity),
          shape: editTableShape,
        }),
      })
      if (!res.ok) throw new Error((await res.json()).error)
      toast.success('Meja diperbarui')
      onRefresh()
    } catch (err: any) {
      toast.error(err.message)
    }
  }

  const handleRemoveFromFloor = (tableId: string) => {
    setLocalPositions(prev => {
      const updated = { ...prev }
      delete updated[tableId]
      return updated
    })
    setIsDirty(true)
    setSelectedTableId(null)
  }

  const handleAutoArrange = () => {
    if (unplacedTables.length === 0 || !activeFloorId) return

    const cols = Math.ceil(Math.sqrt(unplacedTables.length))
    const spacingX = 85 / Math.max(cols, 1)
    const rows = Math.ceil(unplacedTables.length / cols)
    const spacingY = 85 / Math.max(rows, 1)

    const newPositions = { ...localPositions }
    unplacedTables.forEach((t, i) => {
      const col = i % cols
      const row = Math.floor(i / cols)
      newPositions[t.id] = {
        posX: 5 + col * spacingX,
        posY: 5 + row * spacingY,
        floorAreaId: activeFloorId,
      }
    })

    setLocalPositions(newPositions)
    setIsDirty(true)
    toast.success(`${unplacedTables.length} meja di-arrange otomatis`)
  }

  if (loadingAreas) {
    return (
      <div className="flex items-center justify-center h-64">
        <Loader2 className="w-6 h-6 animate-spin text-gray-400" />
      </div>
    )
  }

  return (
    <DndContext sensors={sensors} onDragStart={handleDragStart} onDragEnd={handleDragEnd} onDragCancel={() => setActiveDragId(null)}>
      <div className="card p-0 overflow-hidden">
        {/* Room tabs + controls bar */}
        <div className="flex items-center gap-1 px-3 py-2 border-b border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800/50 overflow-x-auto">
          {floorAreas.map(area => (
            <div key={area.id} className="flex items-center flex-shrink-0">
              {editingRoomId === area.id ? (
                <div className="flex items-center gap-1">
                  <input
                    type="text"
                    value={editRoomName}
                    onChange={e => setEditRoomName(e.target.value)}
                    className="input-field text-xs py-1 px-2 w-28"
                    autoFocus
                    onKeyDown={e => {
                      if (e.key === 'Enter') handleRenameRoom(area.id)
                      if (e.key === 'Escape') setEditingRoomId(null)
                    }}
                  />
                  <button onClick={() => handleRenameRoom(area.id)} className="p-1 text-green-600 hover:bg-green-50 dark:hover:bg-green-900/30 rounded">
                    <Check className="w-3.5 h-3.5" />
                  </button>
                  <button onClick={() => setEditingRoomId(null)} className="p-1 text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded">
                    <X className="w-3.5 h-3.5" />
                  </button>
                </div>
              ) : (
                <button
                  onClick={() => setActiveFloorId(area.id)}
                  className={`
                    px-3 py-1.5 text-sm font-medium rounded-lg transition-colors flex items-center gap-2
                    ${activeFloorId === area.id
                      ? 'bg-orange-100 text-orange-700 dark:bg-orange-900/40 dark:text-orange-300'
                      : 'text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700'
                    }
                  `}
                >
                  {area.name}
                  {activeFloorId === area.id && (
                    <span className="flex items-center gap-0.5 ml-1">
                      <button
                        onClick={(e) => {
                          e.stopPropagation()
                          setEditingRoomId(area.id)
                          setEditRoomName(area.name)
                        }}
                        className="p-0.5 rounded hover:bg-orange-200 dark:hover:bg-orange-800"
                        title="Rename"
                      >
                        <Edit3 className="w-3 h-3" />
                      </button>
                      <button
                        onClick={(e) => {
                          e.stopPropagation()
                          handleDeleteRoom(area.id)
                        }}
                        className="p-0.5 rounded hover:bg-red-200 dark:hover:bg-red-800 text-red-500"
                        title="Hapus ruangan"
                      >
                        <Trash2 className="w-3 h-3" />
                      </button>
                    </span>
                  )}
                </button>
              )}
            </div>
          ))}

          {/* Add room button */}
          {showAddRoom ? (
            <div className="flex items-center gap-1 flex-shrink-0">
              <input
                type="text"
                value={newRoomName}
                onChange={e => setNewRoomName(e.target.value)}
                placeholder="Nama ruangan..."
                className="input-field text-xs py-1 px-2 w-32"
                autoFocus
                onKeyDown={e => {
                  if (e.key === 'Enter') handleAddRoom()
                  if (e.key === 'Escape') { setShowAddRoom(false); setNewRoomName('') }
                }}
              />
              <button
                onClick={handleAddRoom}
                disabled={addingRoom || !newRoomName.trim()}
                className="p-1 text-green-600 hover:bg-green-50 dark:hover:bg-green-900/30 rounded disabled:opacity-50"
              >
                {addingRoom ? <Loader2 className="w-3.5 h-3.5 animate-spin" /> : <Check className="w-3.5 h-3.5" />}
              </button>
              <button onClick={() => { setShowAddRoom(false); setNewRoomName('') }} className="p-1 text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded">
                <X className="w-3.5 h-3.5" />
              </button>
            </div>
          ) : (
            <button
              onClick={() => setShowAddRoom(true)}
              className="flex items-center gap-1 px-2 py-1.5 text-xs text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg flex-shrink-0"
            >
              <Plus className="w-3.5 h-3.5" /> Ruangan
            </button>
          )}

          <div className="flex-1" />

          {/* Save button */}
          <button
            onClick={handleSave}
            disabled={saving || !isDirty}
            className={`
              flex items-center gap-1.5 px-3 py-1.5 text-sm font-medium rounded-lg flex-shrink-0
              ${isDirty
                ? 'bg-orange-500 text-white hover:bg-orange-600 shadow-sm'
                : 'bg-gray-100 text-gray-400 dark:bg-gray-700 dark:text-gray-500 cursor-not-allowed'
              }
            `}
          >
            {saving ? <Loader2 className="w-4 h-4 animate-spin" /> : <Save className="w-4 h-4" />}
            {isDirty ? 'Simpan Layout' : 'Tersimpan'}
          </button>
        </div>

        {/* No floor areas state */}
        {floorAreas.length === 0 ? (
          <div className="flex flex-col items-center justify-center py-16 px-4">
            <div className="w-16 h-16 bg-gray-100 dark:bg-gray-700 rounded-full flex items-center justify-center mb-4">
              <Plus className="w-8 h-8 text-gray-400" />
            </div>
            <h3 className="text-lg font-semibold text-gray-700 dark:text-gray-200 mb-1">Belum Ada Ruangan</h3>
            <p className="text-sm text-gray-500 dark:text-gray-400 mb-4 text-center">
              Buat ruangan terlebih dahulu (misal: Lantai 1, Outdoor, VIP Room)
            </p>
            <div className="flex items-center gap-2">
              <input
                type="text"
                value={newRoomName}
                onChange={e => setNewRoomName(e.target.value)}
                placeholder="Nama ruangan pertama..."
                className="input-field text-sm py-2 px-3 w-48"
                onKeyDown={e => { if (e.key === 'Enter') handleAddRoom() }}
              />
              <button
                onClick={handleAddRoom}
                disabled={addingRoom || !newRoomName.trim()}
                className="btn-primary text-sm"
              >
                {addingRoom ? <Loader2 className="w-4 h-4 animate-spin" /> : <><Plus className="w-4 h-4 inline mr-1" /> Buat</>}
              </button>
            </div>
          </div>
        ) : (
          <>
            {/* Main content: sidebar + canvas */}
            <div className="flex" style={{ height: '500px' }}>
              <UnplacedTablesSidebar
                tables={unplacedTables}
                onAutoArrange={handleAutoArrange}
              />

              <CanvasDroppable canvasRef={canvasRef}>
                {tablesOnFloor.length === 0 && unplacedTables.length === 0 && (
                  <div className="absolute inset-0 flex items-center justify-center">
                    <p className="text-sm text-gray-400 dark:text-gray-500">
                      Belum ada meja. Tambahkan meja di tab &quot;Daftar Meja&quot;.
                    </p>
                  </div>
                )}
                {tablesOnFloor.length === 0 && unplacedTables.length > 0 && (
                  <div className="absolute inset-0 flex items-center justify-center pointer-events-none">
                    <p className="text-sm text-gray-400 dark:text-gray-500">
                      ← Drag meja dari sidebar ke sini
                    </p>
                  </div>
                )}
                {tablesOnFloor.map(table => {
                  const pos = localPositions[table.id]
                  if (!pos) return null
                  return (
                    <FloorPlanTable
                      key={table.id}
                      id={table.id}
                      number={table.number}
                      name={table.name}
                      capacity={table.capacity}
                      shape={table.shape || 'rect'}
                      posX={pos.posX}
                      posY={pos.posY}
                      isSelected={selectedTableId === table.id}
                      onClick={() => setSelectedTableId(selectedTableId === table.id ? null : table.id)}
                    />
                  )
                })}
              </CanvasDroppable>
            </div>

            {/* Edit panel for selected table */}
            {selectedTable && (
              <div className="border-t border-gray-200 dark:border-gray-700 px-4 py-3 bg-gray-50 dark:bg-gray-800/50">
                <div className="flex items-center gap-4 flex-wrap">
                  <span className="text-sm font-medium text-gray-700 dark:text-gray-200">
                    Meja {selectedTable.number}
                  </span>
                  <div className="flex items-center gap-2">
                    <label className="text-xs text-gray-500 dark:text-gray-400">Nama:</label>
                    <input
                      type="text"
                      value={editTableName}
                      onChange={e => setEditTableName(e.target.value)}
                      className="input-field text-sm py-1 px-2 w-32"
                    />
                  </div>
                  <div className="flex items-center gap-2">
                    <label className="text-xs text-gray-500 dark:text-gray-400">Kapasitas:</label>
                    <input
                      type="number"
                      value={editTableCapacity}
                      onChange={e => setEditTableCapacity(e.target.value)}
                      className="input-field text-sm py-1 px-2 w-16"
                      min="1"
                    />
                  </div>
                  <div className="flex items-center gap-2">
                    <label className="text-xs text-gray-500 dark:text-gray-400">Bentuk:</label>
                    <div className="flex gap-1">
                      <button
                        onClick={() => setEditTableShape('rect')}
                        className={`w-8 h-8 rounded border-2 flex items-center justify-center transition-colors ${
                          editTableShape === 'rect'
                            ? 'border-orange-500 bg-orange-50 dark:bg-orange-900/30'
                            : 'border-gray-300 dark:border-gray-600 hover:border-orange-300'
                        }`}
                        title="Kotak"
                      >
                        <div className="w-4 h-4 border-2 border-current rounded-sm" />
                      </button>
                      <button
                        onClick={() => setEditTableShape('circle')}
                        className={`w-8 h-8 rounded border-2 flex items-center justify-center transition-colors ${
                          editTableShape === 'circle'
                            ? 'border-orange-500 bg-orange-50 dark:bg-orange-900/30'
                            : 'border-gray-300 dark:border-gray-600 hover:border-orange-300'
                        }`}
                        title="Bulat"
                      >
                        <div className="w-4 h-4 border-2 border-current rounded-full" />
                      </button>
                    </div>
                  </div>
                  <button
                    onClick={handleUpdateTable}
                    className="btn-primary text-xs py-1.5"
                  >
                    Update
                  </button>
                  <button
                    onClick={() => handleRemoveFromFloor(selectedTable.id)}
                    className="btn-ghost text-xs py-1.5 text-red-500 hover:bg-red-50 dark:hover:bg-red-900/30"
                  >
                    <Trash2 className="w-3.5 h-3.5 mr-1 inline" />
                    Keluarkan
                  </button>
                  <button
                    onClick={() => setSelectedTableId(null)}
                    className="ml-auto p-1.5 text-gray-400 hover:bg-gray-200 dark:hover:bg-gray-700 rounded"
                  >
                    <X className="w-4 h-4" />
                  </button>
                </div>
              </div>
            )}
          </>
        )}
      </div>

      {/* Drag overlay — visual clone that follows cursor */}
      <DragOverlay dropAnimation={null}>
        {activeDragId ? (() => {
          const table = tables.find(t => t.id === activeDragId)
          if (!table) return null
          const isCircle = (table.shape || 'rect') === 'circle'
          return (
            <div className={`
              flex flex-col items-center justify-center
              w-16 h-16 select-none shadow-xl
              ${isCircle ? 'rounded-full' : 'rounded-lg'}
              bg-orange-100 border-2 border-orange-500 dark:bg-orange-900/40 dark:border-orange-400
            `}>
              <span className="font-bold text-lg leading-none text-orange-700 dark:text-orange-300">
                {table.number}
              </span>
              <span className="text-[10px] leading-tight mt-0.5 text-orange-600 dark:text-orange-400">
                {table.capacity}p
              </span>
            </div>
          )
        })() : null}
      </DragOverlay>
    </DndContext>
  )
}
