import { useEffect, useMemo, useState, type CSSProperties } from 'react';

export interface ToolDescriptor {
  name: string;
  description?: string;
  /** JSON Schema-ish parameter spec (we don't parse, just display). */
  parameters?: Record<string, unknown>;
  /** Optional source/server label (e.g. 'platform-service', 'web_search'). */
  source?: string;
  /** Glyph rendered to the left of the name. */
  glyph?: string;
  /** Mark tool as unavailable. */
  disabled?: boolean;
}

export interface ToolPaletteProps {
  /**
   * Tools — either an array OR an MCP-style URL (`mcp://...`) the
   * palette can fetch via the supplied `discover` adapter.
   */
  source: ToolDescriptor[] | string;
  /**
   * When `source` is a string URL, this adapter performs the discovery
   * lookup. Receives the URL, returns the resolved tool list.
   * Default: fetch(url).then(r => r.json()).then(j => j.tools ?? j).
   */
  discover?: (source: string) => Promise<ToolDescriptor[]>;
  /** Called when a tool is selected. */
  onSelect: (tool: ToolDescriptor) => void;
  /** Filter substring (e.g. ‘sea’ matches ‘search’). */
  filter?: string;
  className?: string;
  style?: CSSProperties;
}

const defaultDiscover = async (src: string): Promise<ToolDescriptor[]> => {
  const res = await fetch(src);
  if (!res.ok) throw new Error(`MCP discovery failed: ${res.status}`);
  const body = (await res.json()) as unknown;
  if (Array.isArray(body)) return body as ToolDescriptor[];
  if (body && typeof body === 'object' && Array.isArray((body as { tools?: unknown }).tools)) {
    return (body as { tools: ToolDescriptor[] }).tools;
  }
  return [];
};

/**
 * `<ToolPalette>` — searchable list of tools an LLM can invoke.
 * Powers the "slash-command" menu in `<PromptComposer>` (Wave 2 0.4+).
 *
 * MCP-style discovery: if `source` is a URL string (e.g.
 * `'mcp://platform-service/tools'`) the palette resolves it via the
 * `discover` adapter and renders the resulting tool descriptors. This
 * is the wedge that lets ByteLyst's MCP-first ecosystem expose tools
 * directly to UIs without per-product wiring.
 */
export function ToolPalette({
  source,
  discover = defaultDiscover,
  onSelect,
  filter = '',
  className,
  style,
}: ToolPaletteProps) {
  const [resolved, setResolved] = useState<ToolDescriptor[] | null>(
    Array.isArray(source) ? source : null,
  );
  const [loading, setLoading] = useState<boolean>(typeof source === 'string');
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    if (Array.isArray(source)) {
      setResolved(source);
      setLoading(false);
      setError(null);
      return;
    }
    let cancelled = false;
    setLoading(true);
    setError(null);
    discover(source)
      .then(tools => {
        if (cancelled) return;
        setResolved(tools);
        setLoading(false);
      })
      .catch(err => {
        if (cancelled) return;
        setError(err instanceof Error ? err.message : String(err));
        setLoading(false);
      });
    return () => {
      cancelled = true;
    };
  }, [source, discover]);

  const filtered = useMemo(() => {
    if (!resolved) return [];
    const q = filter.trim().toLowerCase();
    if (!q) return resolved;
    return resolved.filter(
      t =>
        t.name.toLowerCase().includes(q) ||
        t.description?.toLowerCase().includes(q) ||
        t.source?.toLowerCase().includes(q),
    );
  }, [resolved, filter]);

  return (
    <div
      role="listbox"
      aria-label="Available tools"
      data-testid="bl-tool-palette"
      className={className}
      style={{
        background: 'var(--bl-surface-card, #fff)',
        border: '1px solid var(--bl-border, rgba(0,0,0,0.12))',
        borderRadius: 'var(--bl-radius-card, 10px)',
        padding: 'var(--bl-space-1, 4px)',
        maxHeight: 360,
        overflowY: 'auto',
        ...style,
      }}
    >
      {loading && <Status>Discovering tools…</Status>}
      {error && <Status tone="danger">{error}</Status>}
      {!loading && !error && filtered.length === 0 && <Status>No tools match.</Status>}

      {filtered.map(tool => (
        <button
          key={tool.name}
          type="button"
          role="option"
          data-testid={`bl-tool-palette-option-${tool.name}`}
          disabled={tool.disabled}
          onClick={() => onSelect(tool)}
          style={{
            display: 'flex',
            alignItems: 'flex-start',
            gap: 'var(--bl-space-2, 8px)',
            width: '100%',
            padding: 'var(--bl-space-2, 8px) var(--bl-space-3, 12px)',
            background: 'transparent',
            border: 'none',
            borderRadius: 'var(--bl-radius-control, 6px)',
            textAlign: 'left',
            cursor: tool.disabled ? 'not-allowed' : 'pointer',
            color: 'var(--bl-text-primary, inherit)',
            opacity: tool.disabled ? 0.5 : 1,
          }}
        >
          <span
            aria-hidden
            style={{
              fontSize: 16,
              width: 22,
              textAlign: 'center',
              flexShrink: 0,
              color: 'var(--bl-accent, #6366f1)',
            }}
          >
            {tool.glyph ?? '⚙'}
          </span>
          <span style={{ minWidth: 0, flex: 1 }}>
            <div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
              <code
                style={{
                  fontFamily: 'var(--bl-font-mono, ui-monospace, monospace)',
                  fontSize: '0.85rem',
                  fontWeight: 600,
                }}
              >
                {tool.name}
              </code>
              {tool.source && (
                <span
                  style={{
                    fontSize: '0.7rem',
                    color: 'var(--bl-text-tertiary, #888)',
                  }}
                >
                  · {tool.source}
                </span>
              )}
            </div>
            {tool.description && (
              <div
                style={{
                  fontSize: '0.75rem',
                  color: 'var(--bl-text-secondary, #555)',
                  marginTop: 2,
                }}
              >
                {tool.description}
              </div>
            )}
          </span>
        </button>
      ))}
    </div>
  );
}

function Status({
  children,
  tone,
}: {
  children: React.ReactNode;
  tone?: 'danger';
}) {
  return (
    <div
      data-testid="bl-tool-palette-status"
      style={{
        padding: 'var(--bl-space-3, 12px)',
        fontSize: '0.8rem',
        color:
          tone === 'danger'
            ? 'var(--bl-danger, #ef4444)'
            : 'var(--bl-text-tertiary, #888)',
        textAlign: 'center',
      }}
    >
      {children}
    </div>
  );
}
