import type { OpenClawConfig } from "../config/config.js";
import type { PluginSlotsConfig } from "../config/types.plugins.js";
import type { PluginKind } from "./types.js";

export type PluginSlotKey = keyof PluginSlotsConfig;

type SlotPluginRecord = {
  id: string;
  kind?: PluginKind;
};

const SLOT_BY_KIND: Record<PluginKind, PluginSlotKey> = {
  memory: "memory",
};

const DEFAULT_SLOT_BY_KEY: Record<PluginSlotKey, string> = {
  memory: "memory-core",
};

export function slotKeyForPluginKind(kind?: PluginKind): PluginSlotKey | null {
  if (!kind) {
    return null;
  }
  return SLOT_BY_KIND[kind] ?? null;
}

export function defaultSlotIdForKey(slotKey: PluginSlotKey): string {
  return DEFAULT_SLOT_BY_KEY[slotKey];
}

export type SlotSelectionResult = {
  config: OpenClawConfig;
  warnings: string[];
  changed: boolean;
};

export function applyExclusiveSlotSelection(params: {
  config: OpenClawConfig;
  selectedId: string;
  selectedKind?: PluginKind;
  registry?: { plugins: SlotPluginRecord[] };
}): SlotSelectionResult {
  const slotKey = slotKeyForPluginKind(params.selectedKind);
  if (!slotKey) {
    return { config: params.config, warnings: [], changed: false };
  }

  const warnings: string[] = [];
  const pluginsConfig = params.config.plugins ?? {};
  const prevSlot = pluginsConfig.slots?.[slotKey];
  const slots = {
    ...pluginsConfig.slots,
    [slotKey]: params.selectedId,
  };

  const inferredPrevSlot = prevSlot ?? defaultSlotIdForKey(slotKey);
  if (inferredPrevSlot && inferredPrevSlot !== params.selectedId) {
    warnings.push(
      `Exclusive slot "${slotKey}" switched from "${inferredPrevSlot}" to "${params.selectedId}".`,
    );
  }

  const entries = { ...pluginsConfig.entries };
  const disabledIds: string[] = [];
  if (params.registry) {
    for (const plugin of params.registry.plugins) {
      if (plugin.id === params.selectedId) {
        continue;
      }
      if (plugin.kind !== params.selectedKind) {
        continue;
      }
      const entry = entries[plugin.id];
      if (!entry || entry.enabled !== false) {
        entries[plugin.id] = {
          ...entry,
          enabled: false,
        };
        disabledIds.push(plugin.id);
      }
    }
  }

  if (disabledIds.length > 0) {
    warnings.push(
      `Disabled other "${slotKey}" slot plugins: ${disabledIds.toSorted().join(", ")}.`,
    );
  }

  const changed = prevSlot !== params.selectedId || disabledIds.length > 0;

  if (!changed) {
    return { config: params.config, warnings: [], changed: false };
  }

  return {
    config: {
      ...params.config,
      plugins: {
        ...pluginsConfig,
        slots,
        entries,
      },
    },
    warnings,
    changed: true,
  };
}
