'use client'

import { useMemo } from 'react'
import {
  DndContext,
  KeyboardSensor,
  PointerSensor,
  closestCenter,
  useSensor,
  useSensors,
  type DragEndEvent,
} from '@dnd-kit/core'
import {
  SortableContext,
  sortableKeyboardCoordinates,
  useSortable,
  verticalListSortingStrategy,
} from '@dnd-kit/sortable'
import { CSS } from '@dnd-kit/utilities'
import {
  Bookmark,
  Code,
  FileText,
  Grid,
  GripVertical,
  HelpCircle,
  Image,
  LayoutGrid,
  LayoutTemplate,
  MousePointer,
  PanelLeftClose,
  PanelLeftOpen,
  Play,
  Plus,
  Star,
  Type,
  type LucideIcon,
} from 'lucide-react'
import { BlockCatalog } from '@actuate-media/cms-core/page-builder'
import type { BuilderNode, PageNode } from '@actuate-media/cms-core'

export interface BuilderSectionsPanelProps {
  tree: PageNode
  selectedNodeId: string | null
  /** Collapsed to a slim rail. State is owned by PageBuilder (persisted). */
  collapsed: boolean
  onToggleCollapsed: () => void
  onSelect: (id: string) => void
  /** Move a top-level section to `toIndex` within the page. */
  onReorder: (id: string, toIndex: number) => void
  onAddSection: () => void
}

interface SectionEntry {
  id: string
  name: string
  meta: string
  icon: LucideIcon
  hidden: boolean
}

/** Same icon-name → component mapping the BlockPicker uses for the catalog. */
const BLOCK_ICONS: Record<string, LucideIcon> = {
  Star,
  Type,
  Image,
  LayoutGrid,
  MousePointer,
  Play,
  Grid,
  HelpCircle,
  FileText,
  Code,
}

function collectBlockTypes(node: BuilderNode, out: string[]): void {
  if (node.type === 'block') {
    out.push(node.settings.blockType)
    return
  }
  if (node.type === 'savedSectionRef') return
  for (const child of node.children) collectBlockTypes(child, out)
}

function humanize(type: string): string {
  return type.charAt(0).toUpperCase() + type.slice(1)
}

/**
 * Builder sections have no user-facing title, so each row derives its name
 * from the section's first block (via the catalog label) and summarizes its
 * contents as the kind label — enough for the editor to recognize and jump
 * between sections without inventing data we don't store.
 */
function buildEntries(tree: PageNode, catalog: BlockCatalog): SectionEntry[] {
  return tree.children.map((node, index) => {
    if (node.type === 'savedSectionRef') {
      return {
        id: node.id,
        name: 'Saved section',
        meta: 'From the section library',
        icon: Bookmark,
        hidden: false,
      }
    }
    const blockTypes: string[] = []
    collectBlockTypes(node, blockTypes)
    const firstType = blockTypes[0]
    const def = firstType ? catalog.get(firstType) : undefined
    return {
      id: node.id,
      name: def?.label ?? (firstType ? humanize(firstType) : `Section ${index + 1}`),
      meta:
        blockTypes.length === 0
          ? 'Empty section'
          : `${blockTypes.length} block${blockTypes.length === 1 ? '' : 's'}`,
      icon: (def && BLOCK_ICONS[def.icon]) ?? LayoutTemplate,
      hidden: node.settings.visibility === 'hidden',
    }
  })
}

const ICON_BUTTON_CLASS =
  'flex h-8 w-8 items-center justify-center rounded-[7px] text-[var(--sub)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--acc-l)] hover:text-[var(--acc)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none'

/**
 * Design-parity left rail for the Page Builder (PageBuilder.html): the page's
 * sections listed in order with drag-to-reorder, click-to-select (which
 * highlights the section on the canvas and opens its settings in the existing
 * right-hand context panel), and an "Add Section" affordance at the bottom.
 */
export function BuilderSectionsPanel({
  tree,
  selectedNodeId,
  collapsed,
  onToggleCollapsed,
  onSelect,
  onReorder,
  onAddSection,
}: BuilderSectionsPanelProps) {
  const catalog = useMemo(() => new BlockCatalog(), [])
  const entries = useMemo(() => buildEntries(tree, catalog), [tree, catalog])

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

  function handleDragEnd(event: DragEndEvent) {
    const { active, over } = event
    if (!over || active.id === over.id) return
    const ids = entries.map((e) => e.id)
    const to = ids.indexOf(String(over.id))
    if (to === -1 || !ids.includes(String(active.id))) return
    onReorder(String(active.id), to)
  }

  if (collapsed) {
    return (
      <nav
        aria-label="Page sections"
        className="flex w-11 shrink-0 flex-col items-center border-r border-[var(--bdr)] bg-[var(--sb)] py-2"
      >
        <button
          type="button"
          onClick={onToggleCollapsed}
          aria-expanded={false}
          aria-label="Expand sections panel"
          className={ICON_BUTTON_CLASS}
        >
          <PanelLeftOpen size={16} aria-hidden />
        </button>
      </nav>
    )
  }

  return (
    <nav
      aria-label="Page sections"
      className="flex w-[280px] shrink-0 flex-col overflow-hidden border-r border-[var(--bdr)] bg-[var(--sb)]"
    >
      <div className="flex items-center justify-between border-b border-[var(--bdr)] py-2 pr-2 pl-3.5">
        <div className="flex items-center gap-2">
          <h2 className="text-[13px] font-medium text-[var(--txt)]">Sections</h2>
          <span className="rounded-[4px] bg-[var(--acc-l)] px-[7px] py-0.5 text-[11px] font-medium text-[var(--acc)] tabular-nums">
            {entries.length}
          </span>
        </div>
        <button
          type="button"
          onClick={onToggleCollapsed}
          aria-expanded
          aria-label="Collapse sections panel"
          className={ICON_BUTTON_CLASS}
        >
          <PanelLeftClose size={16} aria-hidden />
        </button>
      </div>

      <div className="flex-1 overflow-y-auto">
        {entries.length === 0 ? (
          <p className="px-4 py-6 text-center text-[12.5px] text-[var(--muted)]">
            No sections yet. Add one below to start building.
          </p>
        ) : (
          <DndContext
            sensors={sensors}
            collisionDetection={closestCenter}
            onDragEnd={handleDragEnd}
          >
            <SortableContext
              items={entries.map((e) => e.id)}
              strategy={verticalListSortingStrategy}
            >
              <ul aria-label="Sections in page order">
                {entries.map((entry) => (
                  <SortableSectionRow
                    key={entry.id}
                    entry={entry}
                    selected={entry.id === selectedNodeId}
                    onSelect={onSelect}
                  />
                ))}
              </ul>
            </SortableContext>
          </DndContext>
        )}
      </div>

      <div className="border-t border-[var(--bdr)]">
        <button
          type="button"
          onClick={onAddSection}
          className="flex w-full items-center gap-2 px-3.5 py-3 text-[13px] font-medium text-[var(--acc)] transition-colors duration-[var(--motion-fast)] hover:bg-[var(--acc-l)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none focus-visible:ring-inset"
        >
          <Plus size={14} aria-hidden />
          Add Section
        </button>
      </div>
    </nav>
  )
}

interface SortableSectionRowProps {
  entry: SectionEntry
  selected: boolean
  onSelect: (id: string) => void
}

function SortableSectionRow({ entry, selected, onSelect }: SortableSectionRowProps) {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: entry.id,
  })
  const Icon = entry.icon

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

  return (
    <li ref={setNodeRef} style={style} className={isDragging ? 'shadow-[var(--shd2)]' : undefined}>
      <div
        className={`flex items-center gap-1.5 border-b border-[var(--bdr)] py-2 pr-2.5 pl-1.5 transition-colors duration-[var(--motion-fast)] ${
          selected ? 'bg-[var(--acc-l)]' : 'hover:bg-[var(--acc-l)]'
        }`}
      >
        <button
          type="button"
          aria-label={`Drag to reorder ${entry.name}`}
          {...attributes}
          {...listeners}
          className="shrink-0 cursor-grab touch-none rounded p-1 text-[var(--muted)] transition-colors duration-[var(--motion-fast)] hover:text-[var(--acc)] focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none active:cursor-grabbing"
        >
          <GripVertical size={15} aria-hidden />
        </button>
        <button
          type="button"
          onClick={() => onSelect(entry.id)}
          aria-current={selected ? 'true' : undefined}
          className="flex min-w-0 flex-1 items-center gap-2.5 rounded text-left focus-visible:ring-2 focus-visible:ring-[var(--ring)] focus-visible:outline-none"
        >
          <span
            aria-hidden
            className="flex h-7 w-7 shrink-0 items-center justify-center rounded-[7px] bg-[var(--acc-l)] text-[var(--acc)]"
          >
            <Icon size={14} />
          </span>
          <span className="flex min-w-0 flex-col">
            <span
              className={`truncate text-[13px] font-medium ${
                entry.hidden ? 'text-[var(--muted)] line-through' : 'text-[var(--txt)]'
              }`}
            >
              {entry.name}
            </span>
            <span className="truncate text-[11px] text-[var(--muted)]">{entry.meta}</span>
          </span>
        </button>
      </div>
    </li>
  )
}
