'use client';

import * as React from 'react';
import { cn } from '../../lib/utils';
import { getCategoryToken } from './theme/categories';
import { getCategoryIcon } from './node-icons';
import type { NodeTypeDef } from './types';

/** MIME-ish key used to carry a node-type slug across HTML5 drag-and-drop. */
export const NODE_DND_MIME = 'application/x-workflow-node';

export interface NodePaletteProps {
  /** The node-type catalog to list. */
  nodeTypes: NodeTypeDef[];
  /** Optional click handler (e.g. add node at canvas center). */
  onAddNode?: (slug: string) => void;
  className?: string;
}

function matches(nt: NodeTypeDef, query: string): boolean {
  if (!query) return true;
  const q = query.toLowerCase();
  return (
    nt.name.toLowerCase().includes(q) ||
    nt.slug.toLowerCase().includes(q) ||
    nt.category.toLowerCase().includes(q) ||
    (nt.description?.toLowerCase().includes(q) ?? false)
  );
}

function groupByCategory(
  nodeTypes: NodeTypeDef[]
): { category: string; items: NodeTypeDef[] }[] {
  const groups = new Map<string, NodeTypeDef[]>();
  for (const nt of nodeTypes) {
    const list = groups.get(nt.category) ?? [];
    list.push(nt);
    groups.set(nt.category, list);
  }
  return [...groups.entries()].map(([category, items]) => ({ category, items }));
}

/**
 * Draggable palette of {@link NodeTypeDef}s, grouped by category with a search
 * filter. Each item is HTML5-draggable: dragging sets the node-type slug on
 * `dataTransfer` under {@link NODE_DND_MIME} for the canvas to read on drop.
 */
export function NodePalette({ nodeTypes, onAddNode, className }: NodePaletteProps) {
  const [query, setQuery] = React.useState('');

  const groups = React.useMemo(() => {
    const filtered = nodeTypes.filter((nt) => matches(nt, query));
    return groupByCategory(filtered);
  }, [nodeTypes, query]);

  return (
    <div className={cn('flex h-full min-h-0 flex-col', className)}>
      <div className="shrink-0 border-b border-border p-2">
        <input
          type="search"
          role="searchbox"
          aria-label="Filter node types"
          placeholder="Search nodes…"
          value={query}
          onChange={(e) => setQuery(e.target.value)}
          className="w-full rounded-md border border-border bg-background px-2 py-1.5 text-sm outline-none focus:ring-2 focus:ring-primary"
        />
      </div>

      <div className="min-h-0 flex-1 overflow-auto p-2">
        {groups.length === 0 ? (
          <p className="px-1 py-4 text-center text-xs text-muted-foreground">
            No matching nodes.
          </p>
        ) : (
          groups.map(({ category, items }) => {
            const token = getCategoryToken(category);
            return (
              <div key={category} className="mb-3">
                <h4 className="mb-1 px-1 text-[11px] font-semibold uppercase tracking-wide text-muted-foreground">
                  {token.label}
                </h4>
                <ul className="flex flex-col gap-1">
                  {items.map((nt) => {
                    const Icon = getCategoryIcon(token.icon);
                    return (
                      <li key={nt.slug}>
                        <div
                          draggable
                          onDragStart={(e) => {
                            e.dataTransfer.setData(NODE_DND_MIME, nt.slug);
                            e.dataTransfer.effectAllowed = 'move';
                          }}
                          onClick={() => onAddNode?.(nt.slug)}
                          className="flex cursor-grab items-center gap-2 rounded-md border border-border bg-card px-2 py-1.5 text-sm transition-colors hover:bg-accent active:cursor-grabbing"
                          title={nt.description ?? nt.name}
                        >
                          <span
                            className="flex h-6 w-6 shrink-0 items-center justify-center rounded"
                            style={{ background: token.background, color: token.color }}
                          >
                            <Icon className="h-3.5 w-3.5" aria-hidden="true" />
                          </span>
                          <span className="min-w-0 flex-1 truncate text-foreground">
                            {nt.name}
                          </span>
                        </div>
                      </li>
                    );
                  })}
                </ul>
              </div>
            );
          })
        )}
      </div>
    </div>
  );
}
