/**
 * Console bubble plugin system
 *
 * Plugin registry + shared types. To add a new bubble type:
 *   1. Implement the BubblePlugin interface
 *   2. Call registerBubble() to register it
 *   3. Import it in bubbles/index.ts
 */

import type { ComponentType } from 'react';

// ============================================
// Shared bubble data base type
// ============================================

/** Base fields shared by all plugin bubbles */
export interface PluginItemBase {
  id: string;
  _type: string;        // Plugin type identifier; maps to history entry.type when persisted
  timestamp: string;
  [key: string]: unknown;
}

// ============================================
// Bubble component props (injected by ConsoleView)
// ============================================

/** Common props received by each plugin bubble component */
export interface BubbleComponentProps {
  item: PluginItemBase;
  selected: boolean;
  maximized: boolean;
  expandedHeight: number;
  bubbleContentHeight?: number;
  timestamp: string;
  onSelect: () => void;
  onClose: () => void;
  onToggleMaximize: () => void;
  onTitleMouseDown: () => void;
  /** Pass-through extra context (e.g. sleepingBubbles, addBrowserItem, etc.) */
  extra?: Record<string, unknown>;
}

// ============================================
// Plugin definition
// ============================================

export interface BubblePlugin {
  /** Unique type identifier, e.g. 'browser', 'database' */
  type: string;

  /** ID prefix, e.g. 'browser', 'db'; final id = `${prefix}-${timestamp}-${random}` */
  idPrefix: string;

  /** Input router: check if user input matches this plugin */
  match: (input: string) => boolean;

  /** Parse user input → bubble data fields (excluding id / _type / timestamp, generated by the framework) */
  parse: (input: string) => Record<string, unknown>;

  /** Restore bubble data from a persisted history entry */
  fromHistory: (entry: Record<string, unknown>) => Record<string, unknown>;

  /** Serialize to a history entry (excluding shared fields type/id/timestamp) */
  toHistory: (item: PluginItemBase) => Record<string, unknown>;

  /** Bubble render component */
  Component: ComponentType<BubbleComponentProps>;

  /** Cleanup callback on close (e.g. disconnect database connection) */
  onClose?: (item: PluginItemBase) => void | Promise<void>;
}

// ============================================
// Registry
// ============================================

const registry = new Map<string, BubblePlugin>();

export function registerBubble(plugin: BubblePlugin) {
  registry.set(plugin.type, plugin);
}

export function getPlugin(type: string): BubblePlugin | undefined {
  return registry.get(type);
}

/** Iterate all plugins and return the first one matching the input */
export function matchInput(input: string): BubblePlugin | null {
  for (const plugin of registry.values()) {
    if (plugin.match(input)) return plugin;
  }
  return null;
}

export function getAllPlugins(): BubblePlugin[] {
  return Array.from(registry.values());
}

/** Generate a plugin bubble ID */
export function generatePluginItemId(prefix: string): string {
  return `${prefix}-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
}
