import React, { useSyncExternalStore } from 'react';
import { IconButton } from 'folds';
import * as lucide from 'lucide-react';
import { UILocation } from '@paarrot/plugin-manager';
import { Icon, Icons, type IconName } from '../../../components/icons';
import { pluginRegistry } from './PluginAPI';

// ---------------------------------------------------------------------------
// Module-level subscription store — works correctly with React 18 concurrent
// rendering, lazy-mounted components (nav panels, route changes), and popup
// menus that mount fresh after plugins have already loaded.
// ---------------------------------------------------------------------------

type Listener = () => void;
const listeners = new Set<Listener>();
let storeVersion = 0;

export function subscribeToButtons(callback: Listener): () => void {
  listeners.add(callback);
  return () => listeners.delete(callback);
}

export function getStoreVersion(): number {
  return storeVersion;
}

/**
 * Notify all subscribed slots that the button registry has changed.
 * Call this after plugins load or unload.
 */
export function dispatchPluginButtonsChanged(): void {
  storeVersion += 1;
  for (const listener of listeners) {
    listener();
  }
}

interface PluginButtonSlotProps {
  /** The UI location to render buttons for. */
  location: UILocation;
}

function renderPluginButtonIcon(button: {
  icon?: string;
  lucideIcon?: string;
}): React.ReactNode {
  const lucideName =
    button.lucideIcon ??
    (typeof button.icon === 'string' && button.icon.startsWith('lucide:')
      ? button.icon.slice('lucide:'.length)
      : undefined);

  if (lucideName && lucideName in Icons) {
    return <Icon src={Icons[lucideName as IconName]} size="300" />;
  }

  if (lucideName) {
    const IconComponent = (lucide as Record<string, React.ComponentType<{ size?: number; strokeWidth?: number }> | undefined>)[
      lucideName
    ];
    if (IconComponent) {
      return <IconComponent size={18} strokeWidth={2} aria-hidden />;
    }
  }

  return (
    <span aria-hidden style={{ fontSize: '1.1em', lineHeight: 1 }}>
      {button.icon ?? '🔌'}
    </span>
  );
}

/**
 * Renders all plugin-registered buttons for the given UI location.
 * Correctly handles components that mount before OR after plugins load,
 * including popup menus, navigation panels, and concurrent React renders.
 */
export function PluginButtonSlot({ location }: PluginButtonSlotProps): React.ReactElement | null {
  useSyncExternalStore(subscribeToButtons, getStoreVersion);

  const buttons = pluginRegistry.getButtonsForLocation(location);
  if (buttons.length === 0) return null;

  return (
    <>
      {buttons.map((button) => (
        <IconButton
          key={button.id}
          variant="SurfaceVariant"
          size="300"
          radii="300"
          aria-label={button.label}
          title={button.label}
          onClick={() => button.onClick?.()}
        >
          {renderPluginButtonIcon(button)}
        </IconButton>
      ))}
    </>
  );
}
