'use client'

import { useState, useCallback, useMemo } from 'react'
import {
  DndContext,
  closestCenter,
  KeyboardSensor,
  PointerSensor,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core'
import {
  SortableContext,
  sortableKeyboardCoordinates,
  verticalListSortingStrategy,
  useSortable,
  arrayMove,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import {
  Plus,
  GripVertical,
  Trash2,
  ChevronDown,
  ChevronRight,
  Layout,
  Megaphone,
  Columns3,
  Image,
  Quote,
  Play,
  X,
} from 'lucide-react'
import { PRESET_BLOCKS, type BlockTypeDefinition } from './block-types.js'

const BLOCK_ICONS: Record<string, React.ComponentType<{ className?: string }>> = {
  layout: Layout,
  megaphone: Megaphone,
  columns: Columns3,
  image: Image,
  quote: Quote,
  play: Play,
}

interface BlockValue {
  id: string
  type: string
  data: Record<string, unknown>
}

export interface BlockBuilderFieldProps {
  label?: string
  value?: BlockValue[]
  onChange?: (value: BlockValue[]) => void
  blocks?: BlockTypeDefinition[]
  helpText?: string
}

interface BlockFieldProps {
  field: BlockTypeDefinition['fields'][number]
  value: unknown
  onChange: (value: unknown) => void
}

function BlockField({ field, value, onChange }: BlockFieldProps) {
  if (field.type === 'select' && field.options) {
    return (
      <div>
        <label className="mb-1 block text-sm font-medium">
          {field.label}
          {field.required && <span className="ml-0.5 text-[var(--destructive)]">*</span>}
        </label>
        <select
          value={(value as string) ?? ''}
          onChange={(e) => onChange(e.target.value)}
          className="w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm transition-colors outline-none focus:ring-2 focus:ring-[var(--ring)]"
        >
          <option value="">Select...</option>
          {field.options.map((opt) => (
            <option key={opt.value} value={opt.value}>
              {opt.label}
            </option>
          ))}
        </select>
      </div>
    )
  }

  if (field.type === 'richText') {
    return (
      <div>
        <label className="mb-1 block text-sm font-medium">
          {field.label}
          {field.required && <span className="ml-0.5 text-[var(--destructive)]">*</span>}
        </label>
        <textarea
          value={(value as string) ?? ''}
          onChange={(e) => onChange(e.target.value)}
          rows={4}
          className="w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm transition-colors outline-none focus:ring-2 focus:ring-[var(--ring)]"
        />
      </div>
    )
  }

  if (field.type === 'media') {
    return (
      <div>
        <label className="mb-1 block text-sm font-medium">
          {field.label}
          {field.required && <span className="ml-0.5 text-[var(--destructive)]">*</span>}
        </label>
        <div className="flex items-center gap-3 rounded-md border border-dashed border-[var(--border)] p-3">
          <div className="flex h-12 w-12 shrink-0 items-center justify-center rounded-md bg-[var(--muted)]">
            <Image className="h-5 w-5 text-[var(--muted-foreground)]" />
          </div>
          <span className="text-sm text-[var(--muted-foreground)]">
            {value ? 'Media selected' : 'No media selected'}
          </span>
        </div>
      </div>
    )
  }

  return (
    <div>
      <label className="mb-1 block text-sm font-medium">
        {field.label}
        {field.required && <span className="ml-0.5 text-[var(--destructive)]">*</span>}
      </label>
      <input
        type="text"
        value={(value as string) ?? ''}
        onChange={(e) => onChange(e.target.value)}
        required={field.required}
        className="w-full rounded-md border border-[var(--border)] bg-[var(--input-background)] px-3 py-2 text-sm transition-colors outline-none focus:ring-2 focus:ring-[var(--ring)]"
      />
    </div>
  )
}

interface SortableBlockProps {
  block: BlockValue
  blockDef: BlockTypeDefinition | undefined
  expanded: boolean
  onToggle: () => void
  onRemove: () => void
  onFieldChange: (fieldName: string, fieldValue: unknown) => void
}

function SortableBlock({
  block,
  blockDef,
  expanded,
  onToggle,
  onRemove,
  onFieldChange,
}: SortableBlockProps) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: block.id,
  })

  const style: React.CSSProperties = {
    transform: CSS.Transform.toString(transform),
    transition,
    opacity: isDragging ? 0.5 : 1,
    zIndex: isDragging ? 10 : undefined,
  }

  const IconComponent = blockDef ? BLOCK_ICONS[blockDef.icon] : undefined

  return (
    <div
      ref={setNodeRef}
      style={style}
      className="rounded-md border border-[var(--border)] bg-[var(--card)]"
    >
      <div className="flex items-center gap-2 border-b border-[var(--border)] px-3 py-2">
        <button
          type="button"
          className="cursor-grab touch-none text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
          {...attributes}
          {...listeners}
        >
          <GripVertical className="h-4 w-4" />
        </button>

        {IconComponent && <IconComponent className="h-4 w-4 text-[var(--muted-foreground)]" />}

        <button
          type="button"
          onClick={onToggle}
          className="flex flex-1 items-center gap-1.5 text-sm font-medium"
        >
          {blockDef?.label ?? block.type}
          {expanded ? (
            <ChevronDown className="h-3.5 w-3.5 text-[var(--muted-foreground)]" />
          ) : (
            <ChevronRight className="h-3.5 w-3.5 text-[var(--muted-foreground)]" />
          )}
        </button>

        <button
          type="button"
          onClick={onRemove}
          className="text-[var(--muted-foreground)] hover:text-[var(--destructive)]"
          aria-label="Remove block"
        >
          <Trash2 className="h-4 w-4" />
        </button>
      </div>

      {expanded && blockDef && (
        <div className="space-y-4 p-4">
          {blockDef.fields.map((field) => (
            <BlockField
              key={field.name}
              field={field}
              value={block.data[field.name]}
              onChange={(val) => onFieldChange(field.name, val)}
            />
          ))}
        </div>
      )}

      {expanded && !blockDef && (
        <div className="p-4 text-sm text-[var(--muted-foreground)]">
          Unknown block type: <code>{block.type}</code>
        </div>
      )}
    </div>
  )
}

export function BlockBuilderField({
  label,
  value = [],
  onChange,
  blocks: customBlocks,
  helpText,
}: BlockBuilderFieldProps) {
  const [expandedIds, setExpandedIds] = useState<Set<string>>(new Set())
  const [pickerOpen, setPickerOpen] = useState(false)

  const allBlockTypes = useMemo(() => {
    if (!customBlocks?.length) return PRESET_BLOCKS
    const customTypes = new Set(customBlocks.map((b) => b.type))
    const filtered = PRESET_BLOCKS.filter((b) => !customTypes.has(b.type))
    return [...filtered, ...customBlocks]
  }, [customBlocks])

  const blockDefMap = useMemo(() => {
    const map = new Map<string, BlockTypeDefinition>()
    for (const def of allBlockTypes) {
      map.set(def.type, def)
    }
    return map
  }, [allBlockTypes])

  const sensors = useSensors(
    useSensor(PointerSensor, { activationConstraint: { distance: 5 } }),
    useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates }),
  )

  const handleDragEnd = useCallback(
    (event: DragEndEvent) => {
      const { active, over } = event
      if (!over || active.id === over.id) return

      const oldIndex = value.findIndex((b) => b.id === active.id)
      const newIndex = value.findIndex((b) => b.id === over.id)
      if (oldIndex === -1 || newIndex === -1) return

      onChange?.(arrayMove(value, oldIndex, newIndex))
    },
    [value, onChange],
  )

  function addBlock(type: string) {
    const newBlock: BlockValue = {
      id: crypto.randomUUID(),
      type,
      data: {},
    }
    const newId = newBlock.id
    onChange?.([...value, newBlock])
    setExpandedIds((prev) => new Set(prev).add(newId))
    setPickerOpen(false)
  }

  function removeBlock(id: string) {
    onChange?.(value.filter((b) => b.id !== id))
    setExpandedIds((prev) => {
      const next = new Set(prev)
      next.delete(id)
      return next
    })
  }

  function toggleExpand(id: string) {
    setExpandedIds((prev) => {
      const next = new Set(prev)
      if (next.has(id)) {
        next.delete(id)
      } else {
        next.add(id)
      }
      return next
    })
  }

  function updateBlockField(blockId: string, fieldName: string, fieldValue: unknown) {
    onChange?.(
      value.map((b) =>
        b.id === blockId ? { ...b, data: { ...b.data, [fieldName]: fieldValue } } : b,
      ),
    )
  }

  const blockIds = value.map((b) => b.id)

  return (
    <div>
      {label && <label className="mb-2 block text-sm font-medium">{label}</label>}

      <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
        <SortableContext items={blockIds} strategy={verticalListSortingStrategy}>
          <div className="space-y-2">
            {value.map((block) => (
              <SortableBlock
                key={block.id}
                block={block}
                blockDef={blockDefMap.get(block.type)}
                expanded={expandedIds.has(block.id)}
                onToggle={() => toggleExpand(block.id)}
                onRemove={() => removeBlock(block.id)}
                onFieldChange={(name, val) => updateBlockField(block.id, name, val)}
              />
            ))}
          </div>
        </SortableContext>
      </DndContext>

      {value.length === 0 && (
        <div className="rounded-md border border-dashed border-[var(--border)] px-4 py-8 text-center text-sm text-[var(--muted-foreground)]">
          No blocks added yet. Click &ldquo;Add Block&rdquo; to get started.
        </div>
      )}

      <div className="relative mt-3">
        <button
          type="button"
          onClick={() => setPickerOpen((prev) => !prev)}
          className="inline-flex items-center gap-1.5 rounded-md border border-dashed border-[var(--border)] px-3 py-2 text-sm text-[var(--muted-foreground)] transition-colors hover:border-[var(--foreground)] hover:text-[var(--foreground)]"
        >
          <Plus className="h-4 w-4" />
          Add Block
        </button>
      </div>

      {pickerOpen && (
        <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/50">
          <div className="w-full max-w-2xl rounded-lg border border-[var(--border)] bg-[var(--card)] shadow-xl">
            <div className="flex items-center justify-between border-b border-[var(--border)] px-5 py-4">
              <h3 className="text-base font-semibold">Add Block</h3>
              <button
                type="button"
                onClick={() => setPickerOpen(false)}
                className="text-[var(--muted-foreground)] hover:text-[var(--foreground)]"
                aria-label="Close"
              >
                <X className="h-5 w-5" />
              </button>
            </div>
            <div className="grid grid-cols-2 gap-3 p-5 sm:grid-cols-3">
              {allBlockTypes.map((bt) => {
                const Icon = BLOCK_ICONS[bt.icon]
                return (
                  <button
                    key={bt.type}
                    type="button"
                    onClick={() => addBlock(bt.type)}
                    className="flex flex-col items-start gap-1.5 rounded-md border border-[var(--border)] p-3 text-left transition-colors hover:border-[var(--primary)] hover:bg-[var(--accent)]"
                  >
                    {Icon && <Icon className="h-5 w-5 text-[var(--primary)]" />}
                    <span className="text-sm font-medium">{bt.label}</span>
                    <span className="text-xs leading-snug text-[var(--muted-foreground)]">
                      {bt.description}
                    </span>
                  </button>
                )
              })}
            </div>
          </div>
        </div>
      )}

      {helpText && <p className="mt-1 text-xs text-[var(--muted-foreground)]">{helpText}</p>}
    </div>
  )
}
