import { memo, useState, useRef, useCallback, useEffect } from 'react'
import { useDragRegion } from '../hooks/useDragRegion'
import type { VaultEntry, NoteStatus } from '../types'
import { cn } from '@/lib/utils'
import { X } from 'lucide-react'
import { Plus, Columns, ArrowsOutSimple, ArrowLeft, ArrowRight } from '@phosphor-icons/react'

interface Tab {
  entry: VaultEntry
  content: string
}

interface TabBarProps {
  tabs: Tab[]
  activeTabPath: string | null
  getNoteStatus?: (path: string) => NoteStatus
  onSwitchTab: (path: string) => void
  onCloseTab: (path: string) => void
  onCreateNote?: () => void
  onReorderTabs?: (fromIndex: number, toIndex: number) => void
  onRenameTab?: (path: string, newTitle: string) => void
  canGoBack?: boolean
  canGoForward?: boolean
  onGoBack?: () => void
  onGoForward?: () => void
}

const DISABLED_ICON_STYLE = { opacity: 0.4, cursor: 'not-allowed' } as const

// --- Inline edit ---

/** Inline edit input shown when user double-clicks a tab title. */
function InlineTabEdit({ initialValue, onSave, onCancel }: {
  initialValue: string
  onSave: (value: string) => void
  onCancel: () => void
}) {
  const [value, setValue] = useState(initialValue)
  const inputRef = useRef<HTMLInputElement>(null)
  // Guard against double-fire: Enter calls handleSave, then React unmounts
  // the input (editingPath → null), which triggers blur → handleSave again.
  const committedRef = useRef(false)

  useEffect(() => {
    inputRef.current?.select()
  }, [])

  const handleSave = useCallback(() => {
    if (committedRef.current) return
    committedRef.current = true
    const trimmed = value.trim()
    if (trimmed && trimmed !== initialValue) {
      onSave(trimmed)
    } else {
      onCancel()
    }
  }, [value, initialValue, onSave, onCancel])

  return (
    <input
      ref={inputRef}
      value={value}
      onChange={(e) => setValue(e.target.value)}
      onKeyDown={(e) => {
        if (e.key === 'Enter') handleSave()
        if (e.key === 'Escape') onCancel()
        e.stopPropagation()
      }}
      onBlur={handleSave}
      onClick={(e) => e.stopPropagation()}
      onMouseDown={(e) => e.stopPropagation()}
      draggable={false}
      onDragStart={(e) => e.preventDefault()}
      style={{
        width: '100%',
        minWidth: 40,
        maxWidth: 150,
        background: 'var(--background)',
        border: '1px solid var(--ring)',
        borderRadius: 3,
        padding: '2px 6px',
        fontSize: 12,
        fontWeight: 500,
        color: 'var(--foreground)',
        outline: 'none',
        fontFamily: 'inherit',
      }}
    />
  )
}

// --- Drag-and-drop helpers ---

function computeDropTarget(dragIdx: number | null, dropIdx: number | null): number | null {
  if (dragIdx === null || dropIdx === null || dragIdx === dropIdx) return null
  const toIndex = dropIdx > dragIdx ? dropIdx - 1 : dropIdx
  return toIndex !== dragIdx ? toIndex : null
}

function computeInsertIndex(e: React.DragEvent<HTMLDivElement>, index: number): number {
  const rect = e.currentTarget.getBoundingClientRect()
  return e.clientX < rect.left + rect.width / 2 ? index : index + 1
}

function useTabDrag(onReorderTabs?: (from: number, to: number) => void) {
  const [dragIndex, setDragIndex] = useState<number | null>(null)
  const [dropIndex, setDropIndex] = useState<number | null>(null)
  // Refs mirror state so event handlers always read the latest values,
  // avoiding stale closures when dragover and drop fire in the same frame.
  const dragIndexRef = useRef<number | null>(null)
  const dropIndexRef = useRef<number | null>(null)
  const dragNodeRef = useRef<HTMLDivElement | null>(null)
  const onReorderRef = useRef(onReorderTabs)
  useEffect(() => { onReorderRef.current = onReorderTabs })

  const resetDrag = useCallback(() => {
    if (dragNodeRef.current) dragNodeRef.current.style.opacity = ''
    dragNodeRef.current = null
    dragIndexRef.current = null
    dropIndexRef.current = null
    setDragIndex(null)
    setDropIndex(null)
  }, [])

  const handleDragStart = useCallback((e: React.DragEvent<HTMLDivElement>, index: number) => {
    dragIndexRef.current = index
    setDragIndex(index)
    e.dataTransfer.effectAllowed = 'move'
    e.dataTransfer.setData('text/plain', String(index))
    dragNodeRef.current = e.currentTarget
    requestAnimationFrame(() => {
      if (dragNodeRef.current) dragNodeRef.current.style.opacity = '0.5'
    })
  }, [])

  const handleDragOver = useCallback((e: React.DragEvent<HTMLDivElement>, index: number) => {
    e.preventDefault()
    e.dataTransfer.dropEffect = 'move'
    const currentDrag = dragIndexRef.current
    if (currentDrag === null || currentDrag === index) {
      dropIndexRef.current = null
      setDropIndex(null)
      return
    }
    const idx = computeInsertIndex(e, index)
    dropIndexRef.current = idx
    setDropIndex(idx)
  }, [])

  const handleDrop = useCallback((e: React.DragEvent<HTMLDivElement>) => {
    e.preventDefault()
    const toIndex = computeDropTarget(dragIndexRef.current, dropIndexRef.current)
    if (toIndex !== null && onReorderRef.current) {
      onReorderRef.current(dragIndexRef.current!, toIndex)
    }
    resetDrag()
  }, [resetDrag])

  const handleBarDragLeave = useCallback((e: React.DragEvent<HTMLDivElement>) => {
    const related = e.relatedTarget as HTMLElement | null
    if (!e.currentTarget.contains(related)) {
      dropIndexRef.current = null
      setDropIndex(null)
    }
  }, [])

  return { dragIndex, dropIndex, handleDragStart, handleDragEnd: resetDrag, handleDragOver, handleDrop, handleBarDragLeave }
}

// --- Sub-components ---

function DropIndicator({ side }: { side: 'left' | 'right' }) {
  return (
    <div style={{
      position: 'absolute', [side]: -1, top: 8, bottom: 8,
      width: 2, background: 'var(--primary)', borderRadius: 1, zIndex: 10,
    }} />
  )
}

const STATUS_DOT: Record<string, { color: string; testId: string; title: string }> = {
  new: { color: 'var(--accent-green)', testId: 'tab-new-indicator', title: 'New (uncommitted)' },
  modified: { color: 'var(--accent-orange)', testId: 'tab-modified-indicator', title: 'Modified (uncommitted)' },
}

function StatusDot({ status }: { status: NoteStatus }) {
  const cfg = STATUS_DOT[status]
  if (!cfg) return null
  return (
    <span
      className="shrink-0"
      style={{ width: 6, height: 6, borderRadius: '50%', background: cfg.color }}
      data-testid={cfg.testId}
      title={cfg.title}
    />
  )
}

function TabItem({ tab, isActive, isEditing, noteStatus, isDragging, showDropBefore, showDropAfter, onSwitch, onClose, onDoubleClick, onRenameSave, onRenameCancel, dragProps }: {
  tab: Tab
  isActive: boolean
  isEditing: boolean
  noteStatus: NoteStatus
  isDragging: boolean
  showDropBefore: boolean
  showDropAfter: boolean
  onSwitch: () => void
  onClose: () => void
  onDoubleClick: () => void
  onRenameSave: (newTitle: string) => void
  onRenameCancel: () => void
  dragProps: React.HTMLAttributes<HTMLDivElement>
}) {
  return (
    <div
      draggable={!isEditing}
      {...dragProps}
      className={cn(
        "group flex shrink-0 items-center gap-1.5 whitespace-nowrap max-w-[180px] transition-all relative",
        isActive ? "text-foreground" : "text-muted-foreground hover:text-secondary-foreground"
      )}
      style={{
        background: isActive ? 'var(--background)' : 'transparent',
        borderRight: `1px solid ${isActive ? 'var(--border)' : 'var(--sidebar-border)'}`,
        borderBottom: isActive ? 'none' : '1px solid var(--sidebar-border)',
        padding: '0 12px', fontSize: 12,
        fontWeight: isActive ? 500 : 400,
        cursor: isEditing ? 'default' : isDragging ? 'grabbing' : 'grab',
        WebkitAppRegion: 'no-drag',
      } as React.CSSProperties}
      onClick={() => !isEditing && onSwitch()}
    >
      {showDropBefore && <DropIndicator side="left" />}
      {isEditing ? (
        <InlineTabEdit initialValue={tab.entry.title} onSave={onRenameSave} onCancel={onRenameCancel} />
      ) : (
        <span className="truncate" onDoubleClick={(e) => { e.stopPropagation(); onDoubleClick() }}>
          {tab.entry.title}
        </span>
      )}
      <StatusDot status={noteStatus} />
      <button
        className={cn(
          "shrink-0 rounded-sm p-0 bg-transparent border-none text-muted-foreground cursor-pointer transition-opacity hover:bg-accent hover:text-foreground",
          isActive ? "opacity-100" : "opacity-0 group-hover:opacity-100"
        )}
        style={{ lineHeight: 0 }}
        draggable={false}
        onClick={(e) => { e.stopPropagation(); onClose() }}
      >
        <X size={14} />
      </button>
      {showDropAfter && <DropIndicator side="right" />}
    </div>
  )
}

function NavButtons({ canGoBack, canGoForward, onGoBack, onGoForward }: {
  canGoBack?: boolean; canGoForward?: boolean; onGoBack?: () => void; onGoForward?: () => void
}) {
  return (
    <div
      className="flex shrink-0 items-center"
      style={{
        gap: 4, padding: '0 8px',
        borderRight: '1px solid var(--sidebar-border)',
        borderBottom: '1px solid var(--sidebar-border)',
        WebkitAppRegion: 'no-drag',
      } as React.CSSProperties}
    >
      <button
        className={cn(
          "flex items-center justify-center border-none bg-transparent p-0.5 rounded-sm transition-colors",
          canGoBack ? "text-muted-foreground cursor-pointer hover:text-foreground hover:bg-accent" : "text-muted-foreground"
        )}
        style={canGoBack ? undefined : DISABLED_ICON_STYLE}
        disabled={!canGoBack}
        onClick={onGoBack}
        title="Back (⌘[)"
        data-testid="nav-back"
      >
        <ArrowLeft size={15} />
      </button>
      <button
        className={cn(
          "flex items-center justify-center border-none bg-transparent p-0.5 rounded-sm transition-colors",
          canGoForward ? "text-muted-foreground cursor-pointer hover:text-foreground hover:bg-accent" : "text-muted-foreground"
        )}
        style={canGoForward ? undefined : DISABLED_ICON_STYLE}
        disabled={!canGoForward}
        onClick={onGoForward}
        title="Forward (⌘])"
        data-testid="nav-forward"
      >
        <ArrowRight size={15} />
      </button>
    </div>
  )
}

function TabBarActions({ onCreateNote }: { onCreateNote?: () => void }) {
  return (
    <div
      className="flex shrink-0 items-center"
      style={{
        borderLeft: '1px solid var(--border)', borderBottom: '1px solid var(--border)',
        gap: 12, padding: '0 12px', WebkitAppRegion: 'no-drag',
      } as React.CSSProperties}
    >
      <button className="flex items-center justify-center border-none bg-transparent p-0 text-muted-foreground cursor-pointer hover:text-foreground transition-colors" onClick={() => onCreateNote?.()} title="New note">
        <Plus size={16} />
      </button>
      <button className="flex items-center justify-center border-none bg-transparent p-0 text-muted-foreground" style={DISABLED_ICON_STYLE} title="Coming soon" tabIndex={-1}>
        <Columns size={16} />
      </button>
      <button className="flex items-center justify-center border-none bg-transparent p-0 text-muted-foreground" style={DISABLED_ICON_STYLE} title="Coming soon" tabIndex={-1}>
        <ArrowsOutSimple size={16} />
      </button>
    </div>
  )
}

// --- Main TabBar ---

export const TabBar = memo(function TabBar({
  tabs, activeTabPath, getNoteStatus, onSwitchTab, onCloseTab, onCreateNote, onReorderTabs, onRenameTab,
  canGoBack, canGoForward, onGoBack, onGoForward,
}: TabBarProps) {
  const { dragIndex, dropIndex, handleDragStart, handleDragEnd, handleDragOver, handleDrop, handleBarDragLeave } = useTabDrag(onReorderTabs)
  const [editingPath, setEditingPath] = useState<string | null>(null)
  const { onMouseDown: onDragMouseDown } = useDragRegion()

  return (
    <div
      className="flex shrink-0 items-stretch"
      style={{ height: 52, background: 'var(--sidebar)' } as React.CSSProperties}
      onDragLeave={handleBarDragLeave}
    >
      <NavButtons canGoBack={canGoBack} canGoForward={canGoForward} onGoBack={onGoBack} onGoForward={onGoForward} />
      {tabs.map((tab, index) => (
        <TabItem
          key={tab.entry.path}
          tab={tab}
          isActive={tab.entry.path === activeTabPath}
          isEditing={editingPath === tab.entry.path}
          noteStatus={getNoteStatus?.(tab.entry.path) ?? 'clean'}
          isDragging={dragIndex !== null}
          showDropBefore={dropIndex === index}
          showDropAfter={dropIndex === index + 1 && index === tabs.length - 1}
          onSwitch={() => onSwitchTab(tab.entry.path)}
          onClose={() => onCloseTab(tab.entry.path)}
          onDoubleClick={() => onRenameTab && setEditingPath(tab.entry.path)}
          onRenameSave={(newTitle) => { setEditingPath(null); onRenameTab?.(tab.entry.path, newTitle) }}
          onRenameCancel={() => setEditingPath(null)}
          dragProps={{
            onDragStart: (e) => handleDragStart(e, index),
            onDragEnd: handleDragEnd,
            onDragOver: (e) => handleDragOver(e, index),
            onDrop: handleDrop,
          }}
        />
      ))}
      <div className="flex-1" style={{ borderBottom: '1px solid var(--border)', cursor: 'default' }} onMouseDown={onDragMouseDown} />
      <TabBarActions onCreateNote={onCreateNote} />
    </div>
  )
})
