import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { logger } from "../monitoring/logger.js";
import {
  IntegrationError,
  ErrorCode
} from "../errors/index.js";
class SimpleEventBus {
  handlers = /* @__PURE__ */ new Map();
  emit(event, data) {
    const eventHandlers = this.handlers.get(event);
    if (!eventHandlers) return;
    for (const handler of eventHandlers) {
      try {
        const result = handler(data);
        if (result instanceof Promise) {
          result.catch((err) => {
            logger.error(`Event handler error for ${String(event)}:`, err);
          });
        }
      } catch (err) {
        logger.error(`Event handler error for ${String(event)}:`, err);
      }
    }
  }
  on(event, handler) {
    const key = event;
    if (!this.handlers.has(key)) {
      this.handlers.set(key, /* @__PURE__ */ new Set());
    }
    this.handlers.get(key).add(handler);
    return () => {
      this.handlers.get(key)?.delete(handler);
    };
  }
  once(event, handler) {
    const wrappedHandler = (data) => {
      unsubscribe();
      return handler(data);
    };
    const unsubscribe = this.on(event, wrappedHandler);
    return unsubscribe;
  }
  off(event) {
    this.handlers.delete(event);
  }
  /** Clear all event handlers */
  clear() {
    this.handlers.clear();
  }
}
class PluginRegistry {
  plugins = /* @__PURE__ */ new Map();
  eventBus;
  projectRoot;
  frameAccess;
  storageProvider;
  constructor(options) {
    this.projectRoot = options.projectRoot;
    this.frameAccess = options.frameAccess;
    this.storageProvider = options.storageProvider;
    this.eventBus = options.eventBus || new SimpleEventBus();
  }
  /**
   * Get the event bus
   */
  getEventBus() {
    return this.eventBus;
  }
  /**
   * Register and load a plugin
   */
  async load(plugin, config) {
    if (this.plugins.has(plugin.id)) {
      throw new IntegrationError(
        `Plugin ${plugin.id} is already loaded`,
        ErrorCode.MCP_EXECUTION_FAILED,
        { pluginId: plugin.id }
      );
    }
    const context = this.createPluginContext(plugin.id, config || {});
    const registration = {
      plugin,
      state: "loading",
      context
    };
    this.plugins.set(plugin.id, registration);
    try {
      await plugin.init(context);
      registration.state = "active";
      registration.loadedAt = /* @__PURE__ */ new Date();
      if (plugin.watch) {
        registration.watchUnsubscribe = plugin.watch((frame) => {
          this.eventBus.emit("context:updated", {
            pluginId: plugin.id,
            frame
          });
        });
      }
      this.eventBus.emit("plugin:loaded", { pluginId: plugin.id });
      logger.info(`Plugin loaded: ${plugin.id} v${plugin.version}`);
    } catch (error) {
      registration.state = "error";
      registration.error = error instanceof Error ? error : new Error(String(error));
      this.eventBus.emit("plugin:error", {
        pluginId: plugin.id,
        error: registration.error
      });
      throw new IntegrationError(
        `Failed to load plugin ${plugin.id}: ${registration.error.message}`,
        ErrorCode.MCP_EXECUTION_FAILED,
        { pluginId: plugin.id },
        registration.error
      );
    }
  }
  /**
   * Unload a plugin
   */
  async unload(pluginId) {
    const registration = this.plugins.get(pluginId);
    if (!registration) {
      throw new IntegrationError(
        `Plugin ${pluginId} is not loaded`,
        ErrorCode.MCP_TOOL_NOT_FOUND,
        { pluginId }
      );
    }
    registration.state = "unloading";
    try {
      if (registration.watchUnsubscribe) {
        registration.watchUnsubscribe();
      }
      await registration.plugin.destroy();
      this.plugins.delete(pluginId);
      this.eventBus.emit("plugin:unloaded", { pluginId });
      logger.info(`Plugin unloaded: ${pluginId}`);
    } catch (error) {
      registration.state = "error";
      registration.error = error instanceof Error ? error : new Error(String(error));
      throw error;
    }
  }
  /**
   * Get a loaded plugin
   */
  get(pluginId) {
    return this.plugins.get(pluginId)?.plugin;
  }
  /**
   * Get plugin registration
   */
  getRegistration(pluginId) {
    return this.plugins.get(pluginId);
  }
  /**
   * Get all loaded plugins
   */
  getAll() {
    return Array.from(this.plugins.values()).filter((r) => r.state === "active").map((r) => r.plugin);
  }
  /**
   * Get plugins by service type
   */
  getByService(service) {
    return this.getAll().filter((p) => p.service === service);
  }
  /**
   * Sync all active plugins
   */
  async syncAll() {
    const results = /* @__PURE__ */ new Map();
    for (const [pluginId, registration] of this.plugins) {
      if (registration.state !== "active") continue;
      try {
        const frames = await registration.plugin.sync();
        results.set(pluginId, frames);
        this.eventBus.emit("context:synced", { pluginId, frames });
      } catch (error) {
        logger.error(`Sync failed for plugin ${pluginId}:`, error);
        registration.error = error instanceof Error ? error : new Error(String(error));
      }
    }
    return results;
  }
  /**
   * Execute a plugin action
   */
  async executeAction(pluginId, action, params) {
    const registration = this.plugins.get(pluginId);
    if (!registration) {
      throw new IntegrationError(
        `Plugin ${pluginId} is not loaded`,
        ErrorCode.MCP_TOOL_NOT_FOUND,
        { pluginId }
      );
    }
    if (registration.state !== "active") {
      throw new IntegrationError(
        `Plugin ${pluginId} is not active (state: ${registration.state})`,
        ErrorCode.MCP_EXECUTION_FAILED,
        { pluginId, state: registration.state }
      );
    }
    const handler = registration.plugin.actions?.[action];
    if (!handler) {
      throw new IntegrationError(
        `Action ${action} not found in plugin ${pluginId}`,
        ErrorCode.MCP_TOOL_NOT_FOUND,
        { pluginId, action }
      );
    }
    return handler(params, registration.context);
  }
  /**
   * List all available actions across plugins
   */
  listActions() {
    const actions = [];
    for (const [pluginId, registration] of this.plugins) {
      if (registration.state !== "active") continue;
      const plugin = registration.plugin;
      if (plugin.actions) {
        for (const action of Object.keys(plugin.actions)) {
          actions.push({
            pluginId,
            action,
            service: plugin.service
          });
        }
      }
    }
    return actions;
  }
  /**
   * Unload all plugins
   */
  async unloadAll() {
    const pluginIds = Array.from(this.plugins.keys());
    for (const pluginId of pluginIds) {
      try {
        await this.unload(pluginId);
      } catch (error) {
        logger.error(`Failed to unload plugin ${pluginId}:`, error);
      }
    }
    this.eventBus.clear();
  }
  /**
   * Create plugin context
   */
  createPluginContext(pluginId, config) {
    return {
      projectRoot: this.projectRoot,
      frames: this.frameAccess,
      storage: this.storageProvider(pluginId),
      events: this.eventBus,
      logger: this.createPluginLogger(pluginId),
      config
    };
  }
  /**
   * Create scoped logger for plugin
   */
  createPluginLogger(pluginId) {
    const prefix = `[plugin:${pluginId}]`;
    return {
      debug: (message, context) => logger.debug(`${prefix} ${message}`, context),
      info: (message, context) => logger.info(`${prefix} ${message}`, context),
      warn: (message, context) => logger.warn(`${prefix} ${message}`, context),
      error: (message, errorOrContext) => logger.error(`${prefix} ${message}`, errorOrContext)
    };
  }
}
function createLinearPluginConfig() {
  return {
    direction: "bidirectional",
    conflictResolution: "newest_wins",
    syncInterval: 15,
    webhookEnabled: false
  };
}
function createLinearPlugin() {
  let context;
  let syncIntervalId;
  return {
    id: "linear",
    name: "Linear Integration",
    version: "1.0.0",
    service: "linear",
    permissions: [
      "frames:read",
      "frames:write",
      "network:api.linear.app",
      "storage:local"
    ],
    configSchema: {
      type: "object",
      properties: {
        teamId: { type: "string", description: "Linear team ID" },
        direction: {
          type: "string",
          enum: ["bidirectional", "to_linear", "from_linear"],
          default: "bidirectional"
        },
        conflictResolution: {
          type: "string",
          enum: ["linear_wins", "stackmemory_wins", "newest_wins", "manual"],
          default: "newest_wins"
        },
        syncInterval: {
          type: "number",
          description: "Sync interval in minutes (0 to disable)",
          default: 15
        },
        webhookEnabled: { type: "boolean", default: false },
        webhookSecret: { type: "string" }
      }
    },
    async init(ctx) {
      context = ctx;
      const apiKey = process.env["LINEAR_API_KEY"];
      if (!apiKey) {
        throw new IntegrationError(
          "LINEAR_API_KEY environment variable not set",
          ErrorCode.LINEAR_AUTH_FAILED
        );
      }
      ctx.logger.info("Linear plugin initialized");
      const interval = ctx.config["syncInterval"] || 0;
      if (interval > 0) {
        syncIntervalId = setInterval(
          () => {
            this.sync().catch((err) => {
              ctx.logger.error("Auto-sync failed", err);
            });
          },
          interval * 60 * 1e3
        );
        ctx.logger.info(`Auto-sync enabled: every ${interval} minutes`);
      }
    },
    async destroy() {
      if (syncIntervalId) {
        clearInterval(syncIntervalId);
        syncIntervalId = void 0;
      }
      context?.logger.info("Linear plugin destroyed");
      context = void 0;
    },
    async sync() {
      if (!context) {
        throw new IntegrationError(
          "Plugin not initialized",
          ErrorCode.LINEAR_SYNC_FAILED
        );
      }
      context.logger.info("Starting Linear sync");
      const frames = [];
      context.logger.info(`Sync complete: ${frames.length} frames`);
      return frames;
    },
    watch(callback) {
      context?.logger.info("Watch mode enabled");
      return () => {
        context?.logger.info("Watch mode disabled");
      };
    },
    actions: {
      createIssue: async (params, ctx) => {
        ctx.logger.info("Creating Linear issue", { title: params.title });
        throw new IntegrationError(
          "Not implemented - integrate with LinearClient",
          ErrorCode.LINEAR_API_ERROR
        );
      },
      updateIssue: async (params, ctx) => {
        ctx.logger.info("Updating Linear issue", { issueId: params.issueId });
        throw new IntegrationError(
          "Not implemented - integrate with LinearClient",
          ErrorCode.LINEAR_API_ERROR
        );
      },
      transitionIssue: async (params, ctx) => {
        ctx.logger.info("Transitioning Linear issue", params);
        throw new IntegrationError(
          "Not implemented - integrate with LinearClient",
          ErrorCode.LINEAR_API_ERROR
        );
      },
      addComment: async (params, ctx) => {
        ctx.logger.info("Adding comment to Linear issue", {
          issueId: params.issueId
        });
        throw new IntegrationError(
          "Not implemented - integrate with LinearClient",
          ErrorCode.LINEAR_API_ERROR
        );
      },
      getIssue: async (params, ctx) => {
        ctx.logger.info("Getting Linear issue", { issueId: params.issueId });
        throw new IntegrationError(
          "Not implemented - integrate with LinearClient",
          ErrorCode.LINEAR_API_ERROR
        );
      },
      importIssues: async (params, ctx) => {
        ctx.logger.info("Importing issues from Linear", params);
        throw new IntegrationError(
          "Not implemented - integrate with LinearSyncEngine",
          ErrorCode.LINEAR_API_ERROR
        );
      }
    }
  };
}
class InMemoryPluginStorage {
  data = /* @__PURE__ */ new Map();
  prefix;
  constructor(pluginId) {
    this.prefix = `plugin:${pluginId}:`;
  }
  async get(key) {
    return this.data.get(this.prefix + key);
  }
  async set(key, value) {
    this.data.set(this.prefix + key, value);
  }
  async delete(key) {
    this.data.delete(this.prefix + key);
  }
  async keys(prefix) {
    const fullPrefix = this.prefix + (prefix || "");
    const keys = [];
    for (const key of this.data.keys()) {
      if (key.startsWith(fullPrefix)) {
        keys.push(key.slice(this.prefix.length));
      }
    }
    return keys;
  }
}
function createPluginRegistry(options) {
  return new PluginRegistry({
    projectRoot: options.projectRoot,
    frameAccess: options.frameAccess,
    storageProvider: options.storageProvider || ((pluginId) => new InMemoryPluginStorage(pluginId))
  });
}
function createMockFrameAccess() {
  const frames = /* @__PURE__ */ new Map();
  return {
    async getActive() {
      for (const frame of frames.values()) {
        if (frame.state === "active") return frame;
      }
      return void 0;
    },
    async get(frameId) {
      return frames.get(frameId);
    },
    async getContext(_frameId) {
      return void 0;
    },
    async create(options) {
      const frame = {
        frame_id: `frame-${Date.now()}-${Math.random().toString(36).slice(2)}`,
        run_id: "mock-run",
        project_id: "mock-project",
        parent_frame_id: options.parentFrameId,
        depth: options.parentFrameId ? 1 : 0,
        type: options.type,
        name: options.name,
        state: "active",
        inputs: options.inputs || {},
        outputs: {},
        digest_json: {},
        created_at: Date.now()
      };
      frames.set(frame.frame_id, frame);
      return frame;
    },
    async close(frameId, outputs) {
      const frame = frames.get(frameId);
      if (frame) {
        frame.state = "closed";
        frame.outputs = outputs || {};
        frame.closed_at = Date.now();
      }
    }
  };
}
export {
  SimpleEventBus as EventBusImpl,
  InMemoryPluginStorage,
  PluginRegistry,
  PluginRegistry as Registry,
  SimpleEventBus,
  createLinearPlugin,
  createLinearPluginConfig,
  createMockFrameAccess,
  createPluginRegistry
};
//# sourceMappingURL=plugin-system.js.map
