import type { OpenClawConfig } from "../config/types.openclaw.js";
import type {
  AgentToolResultMiddleware,
  AgentToolResultMiddlewareOptions,
} from "./agent-tool-result-middleware-types.js";
import { normalizeAgentToolResultMiddlewareRuntimes } from "./agent-tool-result-middleware.js";
import { buildPluginApi } from "./api-builder.js";
import type { CodexAppServerExtensionFactory } from "./codex-app-server-extension-types.js";
import type {
  PluginAgentEventSubscriptionRegistration,
  PluginControlUiDescriptor,
  PluginRuntimeLifecycleRegistration,
  PluginSessionActionRegistration,
  PluginSessionSchedulerJobRegistration,
  PluginSessionExtensionRegistration,
  PluginToolMetadataRegistration,
  PluginTrustedToolPolicyRegistration,
} from "./host-hooks.js";
import type { MemoryEmbeddingProviderAdapter } from "./memory-embedding-providers.js";
import type { PluginAgentToolResultMiddlewareRegistration } from "./registry-types.js";
import type { PluginRuntime } from "./runtime/types.js";
import type {
  AnyAgentTool,
  AgentHarness,
  CliBackendPlugin,
  OpenClawPluginApi,
  ImageGenerationProviderPlugin,
  MediaUnderstandingProviderPlugin,
  MigrationProviderPlugin,
  MusicGenerationProviderPlugin,
  OpenClawPluginCliCommandDescriptor,
  OpenClawPluginCliRegistrar,
  PluginTextTransformRegistration,
  ProviderPlugin,
  RealtimeTranscriptionProviderPlugin,
  RealtimeVoiceProviderPlugin,
  SpeechProviderPlugin,
  UnifiedModelCatalogProviderPlugin,
  VideoGenerationProviderPlugin,
  WebFetchProviderPlugin,
  WebSearchProviderPlugin,
} from "./types.js";

type CapturedPluginCliRegistration = {
  register: OpenClawPluginCliRegistrar;
  parentPath: string[];
  commands: string[];
  descriptors: OpenClawPluginCliCommandDescriptor[];
};

export type CapturedPluginRegistration = {
  api: OpenClawPluginApi;
  providers: ProviderPlugin[];
  agentHarnesses: AgentHarness[];
  cliRegistrars: CapturedPluginCliRegistration[];
  cliBackends: CliBackendPlugin[];
  textTransforms: PluginTextTransformRegistration[];
  codexAppServerExtensionFactories: CodexAppServerExtensionFactory[];
  agentToolResultMiddlewares: PluginAgentToolResultMiddlewareRegistration[];
  speechProviders: SpeechProviderPlugin[];
  realtimeTranscriptionProviders: RealtimeTranscriptionProviderPlugin[];
  realtimeVoiceProviders: RealtimeVoiceProviderPlugin[];
  mediaUnderstandingProviders: MediaUnderstandingProviderPlugin[];
  imageGenerationProviders: ImageGenerationProviderPlugin[];
  videoGenerationProviders: VideoGenerationProviderPlugin[];
  musicGenerationProviders: MusicGenerationProviderPlugin[];
  webFetchProviders: WebFetchProviderPlugin[];
  webSearchProviders: WebSearchProviderPlugin[];
  migrationProviders: MigrationProviderPlugin[];
  memoryEmbeddingProviders: MemoryEmbeddingProviderAdapter[];
  sessionExtensions: PluginSessionExtensionRegistration[];
  trustedToolPolicies: PluginTrustedToolPolicyRegistration[];
  toolMetadata: PluginToolMetadataRegistration[];
  controlUiDescriptors: PluginControlUiDescriptor[];
  runtimeLifecycles: PluginRuntimeLifecycleRegistration[];
  agentEventSubscriptions: PluginAgentEventSubscriptionRegistration[];
  sessionSchedulerJobs: PluginSessionSchedulerJobRegistration[];
  sessionActions: PluginSessionActionRegistration[];
  tools: AnyAgentTool[];
  modelCatalogProviders: UnifiedModelCatalogProviderPlugin[];
};

export function createCapturedPluginRegistration(params?: {
  config?: OpenClawConfig;
  id?: string;
  name?: string;
  registrationMode?: OpenClawPluginApi["registrationMode"];
  source?: string;
}): CapturedPluginRegistration {
  const providers: ProviderPlugin[] = [];
  const agentHarnesses: AgentHarness[] = [];
  const cliRegistrars: CapturedPluginCliRegistration[] = [];
  const cliBackends: CliBackendPlugin[] = [];
  const textTransforms: PluginTextTransformRegistration[] = [];
  const codexAppServerExtensionFactories: CodexAppServerExtensionFactory[] = [];
  const agentToolResultMiddlewares: PluginAgentToolResultMiddlewareRegistration[] = [];
  const speechProviders: SpeechProviderPlugin[] = [];
  const realtimeTranscriptionProviders: RealtimeTranscriptionProviderPlugin[] = [];
  const realtimeVoiceProviders: RealtimeVoiceProviderPlugin[] = [];
  const mediaUnderstandingProviders: MediaUnderstandingProviderPlugin[] = [];
  const imageGenerationProviders: ImageGenerationProviderPlugin[] = [];
  const videoGenerationProviders: VideoGenerationProviderPlugin[] = [];
  const musicGenerationProviders: MusicGenerationProviderPlugin[] = [];
  const webFetchProviders: WebFetchProviderPlugin[] = [];
  const webSearchProviders: WebSearchProviderPlugin[] = [];
  const migrationProviders: MigrationProviderPlugin[] = [];
  const memoryEmbeddingProviders: MemoryEmbeddingProviderAdapter[] = [];
  const sessionExtensions: PluginSessionExtensionRegistration[] = [];
  const trustedToolPolicies: PluginTrustedToolPolicyRegistration[] = [];
  const toolMetadata: PluginToolMetadataRegistration[] = [];
  const controlUiDescriptors: PluginControlUiDescriptor[] = [];
  const runtimeLifecycles: PluginRuntimeLifecycleRegistration[] = [];
  const agentEventSubscriptions: PluginAgentEventSubscriptionRegistration[] = [];
  const sessionSchedulerJobs: PluginSessionSchedulerJobRegistration[] = [];
  const sessionActions: PluginSessionActionRegistration[] = [];
  let capturedSessionTurnCount = 0;
  const tools: AnyAgentTool[] = [];
  const modelCatalogProviders: UnifiedModelCatalogProviderPlugin[] = [];
  const pluginId = params?.id ?? "captured-plugin-registration";
  const pluginName = params?.name ?? "Captured Plugin Registration";
  const pluginSource = params?.source ?? "captured-plugin-registration";
  const noopLogger = {
    info() {},
    warn() {},
    error() {},
    debug() {},
  };

  return {
    providers,
    agentHarnesses,
    cliRegistrars,
    cliBackends,
    textTransforms,
    codexAppServerExtensionFactories,
    agentToolResultMiddlewares,
    speechProviders,
    realtimeTranscriptionProviders,
    realtimeVoiceProviders,
    mediaUnderstandingProviders,
    imageGenerationProviders,
    videoGenerationProviders,
    musicGenerationProviders,
    webFetchProviders,
    webSearchProviders,
    migrationProviders,
    memoryEmbeddingProviders,
    sessionExtensions,
    trustedToolPolicies,
    toolMetadata,
    controlUiDescriptors,
    runtimeLifecycles,
    agentEventSubscriptions,
    sessionSchedulerJobs,
    sessionActions,
    tools,
    modelCatalogProviders,
    api: buildPluginApi({
      id: pluginId,
      name: pluginName,
      source: pluginSource,
      registrationMode: params?.registrationMode ?? "full",
      config: params?.config ?? ({} as OpenClawConfig),
      runtime: {} as PluginRuntime,
      logger: noopLogger,
      resolvePath: (input) => input,
      handlers: {
        registerCli(registrar, opts) {
          const parentPath = (opts?.parentPath ?? [])
            .map((segment) => segment.trim())
            .filter(Boolean);
          const descriptors = (opts?.descriptors ?? [])
            .map((descriptor) => ({
              name: descriptor.name.trim(),
              description: descriptor.description.trim(),
              hasSubcommands: descriptor.hasSubcommands,
            }))
            .filter((descriptor) => descriptor.name && descriptor.description);
          const commands = [
            ...(opts?.commands ?? []),
            ...descriptors.map((descriptor) => descriptor.name),
          ]
            .map((command) => command.trim())
            .filter(Boolean);
          if (commands.length === 0) {
            return;
          }
          cliRegistrars.push({
            register: registrar,
            parentPath,
            commands,
            descriptors,
          });
        },
        registerProvider(provider: ProviderPlugin) {
          providers.push(provider);
        },
        registerModelCatalogProvider(provider: UnifiedModelCatalogProviderPlugin) {
          modelCatalogProviders.push(provider);
        },
        registerAgentHarness(harness: AgentHarness) {
          agentHarnesses.push(harness);
        },
        registerCodexAppServerExtensionFactory(factory: CodexAppServerExtensionFactory) {
          codexAppServerExtensionFactories.push(factory);
        },
        registerAgentToolResultMiddleware(
          handler: AgentToolResultMiddleware,
          options?: AgentToolResultMiddlewareOptions,
        ) {
          const runtimes = normalizeAgentToolResultMiddlewareRuntimes(options);
          agentToolResultMiddlewares.push({
            pluginId,
            pluginName,
            rawHandler: handler,
            handler,
            runtimes,
            source: pluginSource,
          });
        },
        registerCliBackend(backend: CliBackendPlugin) {
          cliBackends.push(backend);
        },
        registerTextTransforms(transforms: PluginTextTransformRegistration) {
          textTransforms.push(transforms);
        },
        registerSpeechProvider(provider: SpeechProviderPlugin) {
          speechProviders.push(provider);
        },
        registerRealtimeTranscriptionProvider(provider: RealtimeTranscriptionProviderPlugin) {
          realtimeTranscriptionProviders.push(provider);
        },
        registerRealtimeVoiceProvider(provider: RealtimeVoiceProviderPlugin) {
          realtimeVoiceProviders.push(provider);
        },
        registerMediaUnderstandingProvider(provider: MediaUnderstandingProviderPlugin) {
          mediaUnderstandingProviders.push(provider);
        },
        registerImageGenerationProvider(provider: ImageGenerationProviderPlugin) {
          imageGenerationProviders.push(provider);
        },
        registerVideoGenerationProvider(provider: VideoGenerationProviderPlugin) {
          videoGenerationProviders.push(provider);
        },
        registerMusicGenerationProvider(provider: MusicGenerationProviderPlugin) {
          musicGenerationProviders.push(provider);
        },
        registerWebFetchProvider(provider: WebFetchProviderPlugin) {
          webFetchProviders.push(provider);
        },
        registerWebSearchProvider(provider: WebSearchProviderPlugin) {
          webSearchProviders.push(provider);
        },
        registerMigrationProvider(provider: MigrationProviderPlugin) {
          migrationProviders.push(provider);
        },
        registerMemoryEmbeddingProvider(adapter: MemoryEmbeddingProviderAdapter) {
          memoryEmbeddingProviders.push(adapter);
        },
        registerSessionExtension(extension: PluginSessionExtensionRegistration) {
          sessionExtensions.push(extension);
        },
        registerTrustedToolPolicy(policy: PluginTrustedToolPolicyRegistration) {
          trustedToolPolicies.push(policy);
        },
        registerToolMetadata(metadata: PluginToolMetadataRegistration) {
          toolMetadata.push(metadata);
        },
        registerControlUiDescriptor(descriptor: PluginControlUiDescriptor) {
          controlUiDescriptors.push(descriptor);
        },
        registerRuntimeLifecycle(lifecycle: PluginRuntimeLifecycleRegistration) {
          runtimeLifecycles.push(lifecycle);
        },
        registerAgentEventSubscription(subscription: PluginAgentEventSubscriptionRegistration) {
          agentEventSubscriptions.push(subscription);
        },
        emitAgentEvent: () => ({ emitted: false, reason: "captured registration" }),
        registerSessionSchedulerJob(job: PluginSessionSchedulerJobRegistration) {
          sessionSchedulerJobs.push(job);
          return {
            id: job.id,
            pluginId,
            sessionKey: job.sessionKey,
            kind: job.kind,
          };
        },
        registerSessionAction(action: PluginSessionActionRegistration) {
          sessionActions.push(action);
        },
        sendSessionAttachment: async () => ({ ok: false, error: "captured registration" }),
        scheduleSessionTurn: async (schedule) => {
          capturedSessionTurnCount += 1;
          return {
            id: `captured-session-turn-${capturedSessionTurnCount}`,
            pluginId,
            sessionKey: schedule.sessionKey,
            kind: "session-turn",
          };
        },
        unscheduleSessionTurnsByTag: async () => ({ removed: 0, failed: 0 }),
        registerTool(tool) {
          if (typeof tool !== "function") {
            tools.push(tool);
          }
        },
      },
    }),
  };
}

export function capturePluginRegistration(
  params: NonNullable<Parameters<typeof createCapturedPluginRegistration>[0]> & {
    register(api: OpenClawPluginApi): void;
  },
): CapturedPluginRegistration {
  const captured = createCapturedPluginRegistration(params);
  params.register(captured.api);
  return captured;
}
