import { Client } from 'discord.js';
import express from 'express';

export interface Plugin {
  name: string;
  version: string;
  description: string;

  /** Called once when plugin is loaded */
  init(ctx: PluginContext): Promise<void>;

  /** Called when Discord client is ready */
  onReady?(ctx: PluginContext): Promise<void>;

  /** Called to register Express routes */
  registerRoutes?(app: express.Application, ctx: PluginContext): void;

  /** Called to build SSE snapshot data for new clients */
  getSnapshot?(ctx: PluginContext): Record<string, any>;

  /** Called on graceful shutdown */
  destroy?(ctx: PluginContext): Promise<void>;
}

export interface PluginContext {
  client: Client;
  dataDir: string;
  adminPwd: string;
  allowedGuildIds: string[];
}

const loadedPlugins: Plugin[] = [];
const pluginContexts = new Map<string, PluginContext>();

export function registerPlugin(plugin: Plugin, ctx: PluginContext): void {
  loadedPlugins.push(plugin);
  pluginContexts.set(plugin.name, ctx);
  console.log(`[Plugin] Registered: ${plugin.name} v${plugin.version}`);
}

export function getPlugins(): Plugin[] {
  return [...loadedPlugins];
}

export function getPluginCtx(pluginName: string): PluginContext | undefined {
  return pluginContexts.get(pluginName);
}

// ── Voice claim system ──
// Only one plugin can use voice per guild. When a new plugin claims voice,
// the previous claimant's cleanup callback is invoked automatically.
type VoiceClaimCleanup = () => void;
const voiceClaims = new Map<string, { plugin: string; cleanup: VoiceClaimCleanup }>();

export function claimVoice(guildId: string, pluginName: string, cleanup: VoiceClaimCleanup): void {
  const existing = voiceClaims.get(guildId);
  if (existing && existing.plugin !== pluginName) {
    console.log(`[Voice] ${pluginName} claims guild ${guildId}, releasing ${existing.plugin}`);
    existing.cleanup();
  }
  voiceClaims.set(guildId, { plugin: pluginName, cleanup });
}

export function releaseVoice(guildId: string, pluginName: string): void {
  const claim = voiceClaims.get(guildId);
  if (claim?.plugin === pluginName) {
    voiceClaims.delete(guildId);
  }
}
