import * as vscode from "vscode";
import { BridgeClient } from "./bridge/client";
import { BridgeWebSocket } from "./bridge/websocket";
import { isMcpGridRegistered, registerMcpServer } from "./bridge/autoSetup";
import { ServersTreeProvider } from "./providers/serversTreeProvider";
import { InstancesTreeProvider } from "./providers/instancesTreeProvider";
import { MetricsTreeProvider } from "./providers/metricsTreeProvider";
import { MarketplaceTreeProvider } from "./providers/marketplaceTreeProvider";
import { StatusBarManager } from "./utils/statusBar";
import { registerCommands } from "./commands/index";
import { CatalogSyncService } from "./services/catalogSync";
import { SecretStore } from "./services/secretStore";

/**
 * MCP Grid VS Code/Cursor extension entry point.
 *
 * On activation:
 * 1. Auto-registers MCP Grid as an MCP server in Cursor's mcp.json (if not already)
 * 2. Starts the bridge process (management API on port 19420)
 * 3. Connects sidebar tree views to the management API
 * 4. Connects WebSocket for real-time updates
 *
 * The MCP server itself is started by Cursor via the mcp.json entry (stdio transport).
 * That same process also runs the management API on port 19420 for the sidebar.
 */
export function activate(context: vscode.ExtensionContext): void {
  console.log("[MCP Grid] Extension activating...");

  // ---------------------------------------------------------------
  // Step 1: Auto-register in Cursor's MCP config (fire-and-forget)
  // ---------------------------------------------------------------
  try {
    if (!isMcpGridRegistered()) {
      console.log("[MCP Grid] Not registered in Cursor MCP config -- registering now...");
      registerMcpServer().catch((err) =>
        console.warn("[MCP Grid] Auto-register failed (non-fatal):", err)
      );
    } else {
      console.log("[MCP Grid] Already registered in Cursor MCP config.");
    }
  } catch (err) {
    console.warn("[MCP Grid] MCP config check failed (non-fatal):", err);
  }

  // ---------------------------------------------------------------
  // Step 2: Core services
  // ---------------------------------------------------------------
  const client = new BridgeClient();
  const secretStore = new SecretStore(context.secrets);
  // Expose secretStore for commands that need it
  (context as any)._mcpGridSecretStore = secretStore;

  // ---------------------------------------------------------------
  // Step 3: Tree view providers (sidebar panels) -- register FIRST
  //   so the sidebar never shows "no data provider"
  // ---------------------------------------------------------------
  const serversProvider = new ServersTreeProvider(client);
  const instancesProvider = new InstancesTreeProvider(client);
  const metricsProvider = new MetricsTreeProvider(client);
  const marketplaceProvider = new MarketplaceTreeProvider(client);

  context.subscriptions.push(
    vscode.window.registerTreeDataProvider("mcpGrid.servers", serversProvider),
    vscode.window.registerTreeDataProvider(
      "mcpGrid.instances",
      instancesProvider
    ),
    vscode.window.registerTreeDataProvider("mcpGrid.metrics", metricsProvider),
    vscode.window.registerTreeDataProvider(
      "mcpGrid.marketplace",
      marketplaceProvider
    )
  );

  // ---------------------------------------------------------------
  // Step 4: Status bar
  // ---------------------------------------------------------------
  const statusBar = new StatusBarManager(client);
  context.subscriptions.push(statusBar as unknown as vscode.Disposable);

  const pollingInterval = vscode.workspace
    .getConfiguration("mcpGrid")
    .get<number>("pollingInterval", 5000);
  statusBar.startPolling(pollingInterval);

  // ---------------------------------------------------------------
  // Step 5: Commands
  // ---------------------------------------------------------------
  const commandDisposables = registerCommands(
    context,
    client,
    serversProvider,
    instancesProvider,
    metricsProvider,
    marketplaceProvider,
    null
  );
  context.subscriptions.push(...commandDisposables);

  // ---------------------------------------------------------------
  // Step 6: WebSocket real-time updates (deferred, non-fatal)
  // ---------------------------------------------------------------
  let ws: BridgeWebSocket | undefined;
  try {
    ws = new BridgeWebSocket();
    ws.connect();
    context.subscriptions.push(ws as unknown as vscode.Disposable);

    ws.onEvent((event) => {
      try {
        switch (event.type) {
          case "instance_activated":
          case "instance_deactivated":
            instancesProvider.refresh();
            metricsProvider.refresh();
            statusBar.forceUpdate();
            break;
          case "tool_call":
            metricsProvider.refresh();
            break;
          case "server_registered":
          case "server_enabled":
          case "server_disabled":
            serversProvider.refresh();
            break;
          case "error":
            vscode.window.showWarningMessage(
              `MCP Grid: ${event?.data?.message ?? "Unknown error"}`
            );
            break;
        }
      } catch (err) {
        console.warn("[MCP Grid] Error handling WS event (non-fatal):", err);
      }
    });
  } catch (err) {
    console.warn("[MCP Grid] WebSocket setup failed (non-fatal):", err);
  }

  // ---------------------------------------------------------------
  // Step 7: Config change listener
  // ---------------------------------------------------------------
  context.subscriptions.push(
    vscode.workspace.onDidChangeConfiguration((e) => {
      if (e.affectsConfiguration("mcpGrid")) {
        client.refreshConfig();
        if (ws) {
          ws.disconnect();
          ws.connect();
        }
        statusBar.stopPolling();
        const newInterval = vscode.workspace
          .getConfiguration("mcpGrid")
          .get<number>("pollingInterval", 5000);
        statusBar.startPolling(newInterval);
      }
    })
  );

  // ---------------------------------------------------------------
  // Step 8: Deferred view refresh with retry
  //   The management API may take up to ~15s to start if it needs
  //   to wait for the old process to release the port.
  //   Poll every 3s for up to 30s.
  // ---------------------------------------------------------------
  const refreshViews = () => {
    serversProvider.refresh();
    instancesProvider.refresh();
    metricsProvider.refresh();
    marketplaceProvider.refresh();
    statusBar.forceUpdate();
  };

  let bootChecks = 0;
  const maxBootChecks = 10; // 10 x 3s = 30s max
  const bootCheckTimer = setInterval(async () => {
    bootChecks++;
    try {
      const alive = await client.isAlive();
      if (alive) {
        console.log("[MCP Grid] Bridge is reachable -- refreshing views.");
        refreshViews();
        clearInterval(bootCheckTimer);
      } else if (bootChecks >= maxBootChecks) {
        console.log(
          "[MCP Grid] Bridge not reachable after 30s. " +
          "It will start when Cursor loads the MCP server, or use the Start Bridge command."
        );
        clearInterval(bootCheckTimer);
      }
    } catch (err) {
      if (bootChecks >= maxBootChecks) {
        console.warn("[MCP Grid] Boot health-check gave up (non-fatal):", err);
        clearInterval(bootCheckTimer);
      }
    }
  }, 3000);
  context.subscriptions.push({ dispose: () => clearInterval(bootCheckTimer) });

  // ---------------------------------------------------------------
  // Step 9: Catalog sync service (hourly marketplace updates)
  // ---------------------------------------------------------------
  const catalogSync = new CatalogSyncService(context);
  catalogSync.start();
  context.subscriptions.push(catalogSync as unknown as vscode.Disposable);

  console.log("[MCP Grid] Extension activated successfully.");
}

export function deactivate(): void {
  console.log("[MCP Grid] Extension deactivated.");
}
