'use client'

import { useCallback, useMemo, useState, ChangeEvent } from 'react'
import { Handle, Position, NodeProps, useReactFlow } from 'reactflow'
import Combobox from '@/components/editor/Combobox'
import type { ComboboxItem } from '@/components/editor/Combobox'
import { useEditorContext } from '@/components/editor/EditorContext'
import NodeLockIndicator from '@/components/editor/NodeLockIndicator'

type DialogueNodeData = {
  speaker?: string
  characterId?: string
  text: string
}

const RANDOM_COLORS = [
  '#EF4444', '#F97316', '#F59E0B', '#10B981',
  '#3B82F6', '#8B5CF6', '#EC4899', '#14B8A6',
  '#6366F1', '#F43F5E', '#84CC16', '#06B6D4',
]

function randomColor(): string {
  return RANDOM_COLORS[Math.floor(Math.random() * RANDOM_COLORS.length)]
}

export default function DialogueNode({ id, data }: NodeProps<DialogueNodeData>) {
  const { setNodes } = useReactFlow()
  const { characters, onAddCharacter, nodeLocks, onNodeFocus, onNodeBlur } = useEditorContext()

  const lockInfo = nodeLocks.get(id)
  const isLockedByOther = !!lockInfo

  const [showAddForm, setShowAddForm] = useState(false)
  const [newName, setNewName] = useState('')
  const [newColor, setNewColor] = useState(randomColor)

  const characterItems: ComboboxItem[] = useMemo(
    () =>
      characters.map((c) => ({
        id: c.id,
        label: c.name,
        color: c.color,
      })),
    [characters]
  )

  const hasInvalidReference = useMemo(() => {
    if (!data.characterId) return false
    return !characters.some((c) => c.id === data.characterId)
  }, [data.characterId, characters])

  const updateNodeData = useCallback(
    (updates: Partial<DialogueNodeData>) => {
      setNodes((nodes) =>
        nodes.map((node) =>
          node.id === id
            ? { ...node, data: { ...node.data, ...updates } }
            : node
        )
      )
    },
    [id, setNodes]
  )

  const handleCharacterSelect = useCallback(
    (characterId: string) => {
      const character = characters.find((c) => c.id === characterId)
      updateNodeData({
        characterId,
        speaker: character?.name || '',
      })
    },
    [characters, updateNodeData]
  )

  const handleAddNew = useCallback(() => {
    setShowAddForm(true)
    setNewName('')
    setNewColor(randomColor())
  }, [])

  const handleSubmitNew = useCallback(() => {
    if (!newName.trim()) return
    const newId = onAddCharacter(newName.trim(), newColor)
    updateNodeData({
      characterId: newId,
      speaker: newName.trim(),
    })
    setShowAddForm(false)
  }, [newName, newColor, onAddCharacter, updateNodeData])

  const handleCancelNew = useCallback(() => {
    setShowAddForm(false)
  }, [])

  const handleTextChange = useCallback(
    (e: ChangeEvent<HTMLTextAreaElement>) => {
      updateNodeData({ text: e.target.value })
    },
    [updateNodeData]
  )

  const handleFocus = useCallback(() => {
    onNodeFocus(id)
  }, [id, onNodeFocus])

  return (
    <div
      className={`relative min-w-[200px] rounded-lg border-2 ${
        hasInvalidReference
          ? 'border-orange-500 dark:border-orange-400'
          : 'border-blue-500 dark:border-blue-400'
      } bg-blue-50 p-3 shadow-md dark:bg-blue-950`}
      onFocus={handleFocus}
      onBlur={onNodeBlur}
    >
      {isLockedByOther && (
        <NodeLockIndicator lock={lockInfo} color={lockInfo.color} />
      )}
      {isLockedByOther && (
        <div className="absolute inset-0 z-20 flex items-center justify-center rounded-lg bg-black/10">
          <span className="rounded bg-black/70 px-2 py-1 text-xs text-white">
            Being edited by {lockInfo.displayName}
          </span>
        </div>
      )}
      <Handle
        type="target"
        position={Position.Top}
        id="input"
        className="!h-3 !w-3 !border-2 !border-blue-500 !bg-white dark:!bg-zinc-800"
      />

      <div className="mb-2 text-xs font-semibold uppercase tracking-wide text-blue-700 dark:text-blue-300">
        Dialogue
      </div>

      <div className="mb-2">
        <Combobox
          items={characterItems}
          value={data.characterId}
          onChange={handleCharacterSelect}
          placeholder="Select speaker..."
          onAddNew={handleAddNew}
        />
        {hasInvalidReference && (
          <div className="mt-1 text-xs text-orange-600 dark:text-orange-400">
            Character not found
          </div>
        )}
      </div>

      {showAddForm && (
        <div className="mb-2 rounded border border-blue-300 bg-white p-2 dark:border-blue-600 dark:bg-zinc-800">
          <div className="mb-1 text-xs font-medium text-zinc-600 dark:text-zinc-300">
            New character
          </div>
          <div className="flex items-center gap-1.5">
            <input
              type="color"
              value={newColor}
              onChange={(e) => setNewColor(e.target.value)}
              className="h-6 w-6 shrink-0 cursor-pointer rounded border border-zinc-300 dark:border-zinc-600"
            />
            <input
              type="text"
              value={newName}
              onChange={(e) => setNewName(e.target.value)}
              placeholder="Name"
              className="w-full rounded border border-zinc-300 bg-white px-2 py-0.5 text-sm focus:border-blue-500 focus:outline-none dark:border-zinc-600 dark:bg-zinc-700 dark:text-white dark:placeholder-zinc-400"
              onKeyDown={(e) => {
                if (e.key === 'Enter') handleSubmitNew()
                if (e.key === 'Escape') handleCancelNew()
              }}
              autoFocus
            />
          </div>
          <div className="mt-1.5 flex justify-end gap-1">
            <button
              onClick={handleCancelNew}
              className="rounded px-2 py-0.5 text-xs text-zinc-500 hover:bg-zinc-100 dark:text-zinc-400 dark:hover:bg-zinc-700"
            >
              Cancel
            </button>
            <button
              onClick={handleSubmitNew}
              disabled={!newName.trim()}
              className="rounded bg-blue-600 px-2 py-0.5 text-xs text-white hover:bg-blue-700 disabled:opacity-50"
            >
              Add
            </button>
          </div>
        </div>
      )}

      <textarea
        value={data.text || ''}
        onChange={handleTextChange}
        placeholder="Dialogue text..."
        rows={3}
        className="w-full resize-none rounded border border-blue-300 bg-white px-2 py-1 text-sm focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500 dark:border-blue-600 dark:bg-zinc-800 dark:text-white dark:placeholder-zinc-400"
      />

      <Handle
        type="source"
        position={Position.Bottom}
        id="output"
        className="!h-3 !w-3 !border-2 !border-blue-500 !bg-white dark:!bg-zinc-800"
      />
    </div>
  )
}
