import * as vscode from "vscode";
import { BridgeClient } from "../bridge/client";
import {
  isMcpGridRegistered,
  registerMcpServer,
  unregisterMcpServer,
} from "../bridge/autoSetup";
import { ServersTreeProvider, ServerTreeItem } from "../providers/serversTreeProvider";
import { InstancesTreeProvider, InstanceTreeItem } from "../providers/instancesTreeProvider";
import { MetricsTreeProvider } from "../providers/metricsTreeProvider";
import { MarketplaceTreeProvider } from "../providers/marketplaceTreeProvider";
import { DashboardPanel } from "../panels/dashboardPanel";
import { AddServerPanel } from "../panels/addServerPanel";

/**
 * Registers all extension commands.
 * Each command is a thin handler that delegates to the appropriate service.
 */
export function registerCommands(
  context: vscode.ExtensionContext,
  client: BridgeClient,
  serversProvider: ServersTreeProvider,
  instancesProvider: InstancesTreeProvider,
  metricsProvider: MetricsTreeProvider,
  marketplaceProvider: MarketplaceTreeProvider,
  bridgeProcess: { pid: number | undefined; kill: () => void } | null
): vscode.Disposable[] {
  const disposables: vscode.Disposable[] = [];

  // -- Bridge lifecycle --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.startBridge", async () => {
      const alive = await client.isAlive();
      if (alive) {
        vscode.window.showInformationMessage("MCP Grid bridge is already running.");
        return;
      }

      const pythonPath = vscode.workspace
        .getConfiguration("mcpGrid")
        .get<string>("pythonPath", "python3");

      const terminal = vscode.window.createTerminal({
        name: "MCP Grid Bridge",
        shellPath: pythonPath,
        shellArgs: ["-m", "mcp_bridge.server"],
      });
      terminal.show();

      vscode.window.showInformationMessage(
        "Starting MCP Grid bridge... Check the terminal for output."
      );

      // Wait a moment then refresh
      setTimeout(() => {
        serversProvider.refresh();
        instancesProvider.refresh();
        metricsProvider.refresh();
      }, 3000);
    })
  );

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.stopBridge", async () => {
      const alive = await client.isAlive();
      if (!alive) {
        vscode.window.showInformationMessage("MCP Grid bridge is not running.");
        return;
      }

      const confirm = await vscode.window.showWarningMessage(
        "Stop the MCP Grid bridge? All active instances will be terminated.",
        "Stop",
        "Cancel"
      );

      if (confirm === "Stop") {
        // Send shutdown request
        try {
          await client.getStatus(); // Just to confirm it's alive
          vscode.window.showInformationMessage(
            "Please close the MCP Grid Bridge terminal to stop the bridge."
          );
        } catch {
          vscode.window.showInformationMessage("Bridge is already stopped.");
        }
      }
    })
  );

  // -- Server operations --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.refreshServers", () => {
      serversProvider.refresh();
      instancesProvider.refresh();
    })
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.activateServer",
      async (item?: ServerTreeItem) => {
        let serverId: string | undefined;

        if (item) {
          serverId = serversProvider.getServerId(item);
        }

        if (!serverId) {
          serverId = await vscode.window.showInputBox({
            prompt: "Enter the server ID to activate",
            placeHolder: "e.g., playwright-mcp",
          });
        }

        if (!serverId) {
          return;
        }

        try {
          const result = await client.activateServer(serverId);
          vscode.window.showInformationMessage(
            `Server activated. Instance ID: ${result.instance_id}`
          );
          instancesProvider.refresh();
          metricsProvider.refresh();
        } catch (err) {
          vscode.window.showErrorMessage(`Failed to activate server: ${err}`);
        }
      }
    )
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.deactivateServer",
      async (item?: InstanceTreeItem) => {
        let instanceId: string | undefined;

        if (item) {
          instanceId = instancesProvider.getInstanceId(item);
        }

        if (!instanceId) {
          instanceId = await vscode.window.showInputBox({
            prompt: "Enter the instance ID to deactivate",
          });
        }

        if (!instanceId) {
          return;
        }

        try {
          await client.deactivateInstance(instanceId);
          vscode.window.showInformationMessage("Instance deactivated.");
          instancesProvider.refresh();
          metricsProvider.refresh();
        } catch (err) {
          vscode.window.showErrorMessage(`Failed to deactivate: ${err}`);
        }
      }
    )
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.enableServer",
      async (item?: ServerTreeItem) => {
        const serverId = item ? serversProvider.getServerId(item) : undefined;
        if (!serverId) {
          return;
        }

        try {
          await client.enableServer(serverId);
          vscode.window.showInformationMessage(`Server "${serverId}" enabled.`);
          serversProvider.refresh();
        } catch (err) {
          vscode.window.showErrorMessage(`Failed to enable server: ${err}`);
        }
      }
    )
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.disableServer",
      async (item?: ServerTreeItem) => {
        const serverId = item ? serversProvider.getServerId(item) : undefined;
        if (!serverId) {
          return;
        }

        try {
          await client.disableServer(serverId);
          vscode.window.showInformationMessage(`Server "${serverId}" disabled.`);
          serversProvider.refresh();
        } catch (err) {
          vscode.window.showErrorMessage(`Failed to disable server: ${err}`);
        }
      }
    )
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.configureServer",
      async (item?: any) => {
        // Support both ServersTreeProvider items and MarketplaceTreeProvider items
        let serverId: string | undefined;
        if (item?.serverInfo?.id) {
          serverId = item.serverInfo.id;
        } else if (item?.kind && serversProvider.getServerId) {
          serverId = serversProvider.getServerId(item);
        }

        if (!serverId) {
          serverId = await vscode.window.showInputBox({
            prompt: "Enter the server ID to configure",
            placeHolder: "e.g., playwright-mcp",
          });
        }
        if (!serverId) {
          return;
        }

        try {
          const server = await client.getServer(serverId);
          if (!server.config_options || server.config_options.length === 0) {
            vscode.window.showInformationMessage(
              `Server "${server.name || serverId}" has no configurable options.`
            );
            return;
          }

          // Show config options with clear labels showing server name + option step
          const config: Record<string, string> = {};
          const total = server.config_options.length;
          for (let i = 0; i < total; i++) {
            const opt = server.config_options[i];
            const step = `(${i + 1}/${total})`;
            const reqLabel = opt.required ? " [required]" : "";
            const value = await vscode.window.showInputBox({
              title: `Configure "${server.name || serverId}" ${step}`,
              prompt: `${opt.name}${reqLabel}: ${opt.description || `Enter value for ${opt.name}`}`,
              placeHolder: opt.default
                ? `Default: ${opt.default}`
                : `Enter ${opt.name} (${opt.type})`,
              value: opt.default || "",
              ignoreFocusOut: true,
            });
            if (value === undefined) {
              return; // User cancelled the whole flow
            }
            if (value !== "") {
              config[opt.name] = value;
            }
          }

          // Show summary of what was configured
          const summary = Object.entries(config)
            .map(([k, v]) => `  ${k} = ${v}`)
            .join("\n");
          const action = await vscode.window.showInformationMessage(
            `Configuration saved for "${server.name || serverId}":\n${summary || "  (all defaults)"}`,
            "Activate Now",
            "Done"
          );

          if (action === "Activate Now") {
            const result = await client.activateServer(serverId, config);
            vscode.window.showInformationMessage(
              `"${server.name || serverId}" activated! Instance: ${result.instance_id}`
            );
            instancesProvider.refresh();
            metricsProvider.refresh();
            serversProvider.refresh();
          }
        } catch (err) {
          vscode.window.showErrorMessage(`Failed to configure: ${err}`);
        }
      }
    )
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.viewServerDetails",
      async (item?: ServerTreeItem) => {
        const serverId = item ? serversProvider.getServerId(item) : undefined;
        if (!serverId) {
          return;
        }

        try {
          const server = await client.getServer(serverId);
          const detail = [
            `# ${server.name || server.id}`,
            "",
            server.description || "No description",
            "",
            `- **ID:** ${server.id}`,
            `- **Category:** ${server.category}`,
            `- **Transport:** ${server.transport}`,
            `- **Enabled:** ${server.enabled}`,
          ].join("\n");

          const doc = await vscode.workspace.openTextDocument({
            content: detail,
            language: "markdown",
          });
          vscode.window.showTextDocument(doc, { preview: true });
        } catch (err) {
          vscode.window.showErrorMessage(
            `Failed to get server details: ${err}`
          );
        }
      }
    )
  );

  // -- Import config --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.importConfig", async () => {
      const options = ["From File", "From Clipboard"];
      const choice = await vscode.window.showQuickPick(options, {
        placeHolder: "Import MCP configuration from...",
      });

      if (choice === "From File") {
        const uris = await vscode.window.showOpenDialog({
          canSelectMany: false,
          filters: { JSON: ["json"] },
          title: "Select mcp.json file",
        });

        if (uris && uris.length > 0) {
          try {
            const content = await vscode.workspace.fs.readFile(uris[0]);
            const config = JSON.parse(Buffer.from(content).toString("utf-8"));
            const result = await client.importConfig(config);
            vscode.window.showInformationMessage(
              `Imported ${result.imported} server(s) from config file.`
            );
            serversProvider.refresh();
          } catch (err) {
            vscode.window.showErrorMessage(`Failed to import config: ${err}`);
          }
        }
      } else if (choice === "From Clipboard") {
        try {
          const text = await vscode.env.clipboard.readText();
          const config = JSON.parse(text);
          const result = await client.importConfig(config);
          vscode.window.showInformationMessage(
            `Imported ${result.imported} server(s) from clipboard.`
          );
          serversProvider.refresh();
        } catch (err) {
          vscode.window.showErrorMessage(
            `Failed to import from clipboard: ${err}`
          );
        }
      }
    })
  );

  // -- Add Server --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.addServerFromOpenAPI", () => {
      AddServerPanel.createOrShow(client, "openapi");
    })
  );

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.addServerManual", () => {
      AddServerPanel.createOrShow(client, "manual");
    })
  );

  disposables.push(
    vscode.commands.registerCommand(
      "mcpGrid.addServerFromMarketplace",
      async (item?: any) => {
        const serverId = item?.serverInfo?.id;
        const serverName = item?.serverInfo?.name || serverId;
        if (!serverId) {
          vscode.window.showWarningMessage("No server selected.");
          return;
        }

        // Check for config options - prompt user to configure first
        const server = item?.serverInfo;
        let config: Record<string, string> | undefined;

        if (server?.config_options && server.config_options.length > 0) {
          const configChoice = await vscode.window.showInformationMessage(
            `"${serverName}" has ${server.config_options.length} configurable option(s). Configure before activating?`,
            "Configure & Activate",
            "Activate with Defaults",
            "Cancel"
          );

          if (configChoice === "Cancel" || !configChoice) {
            return;
          }

          if (configChoice === "Configure & Activate") {
            config = {};
            for (const opt of server.config_options) {
              const value = await vscode.window.showInputBox({
                prompt: `${opt.description || opt.name}`,
                placeHolder: opt.default || `Enter ${opt.name}`,
                value: opt.default || "",
                title: `Configure: ${opt.name} (${opt.type})`,
              });
              if (value === undefined) {
                return; // User cancelled
              }
              if (value !== "") {
                config[opt.name] = value;
              }
            }
          }
        }

        try {
          await vscode.window.withProgress(
            {
              location: vscode.ProgressLocation.Notification,
              title: `Installing "${serverName}"...`,
              cancellable: false,
            },
            async () => {
              const result = await client.activateServer(serverId, config);
              vscode.window.showInformationMessage(
                `"${serverName}" installed and activated. Instance: ${result.instance_id}`
              );
            }
          );
          instancesProvider.refresh();
          metricsProvider.refresh();
          serversProvider.refresh();
        } catch (err) {
          vscode.window.showErrorMessage(
            `Failed to install "${serverName}": ${err}`
          );
        }
      }
    )
  );

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.refreshMarketplace", () => {
      marketplaceProvider.refresh();
    })
  );

  // -- Dashboard --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.openDashboard", () => {
      DashboardPanel.createOrShow(client);
    })
  );

  // -- Metrics --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.refreshMetrics", () => {
      metricsProvider.refresh();
    })
  );

  // -- MCP Server Registration --

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.registerMcpServer", async () => {
      if (isMcpGridRegistered()) {
        vscode.window.showInformationMessage(
          "MCP Grid is already registered as an MCP server in Cursor."
        );
        return;
      }
      await registerMcpServer();
    })
  );

  disposables.push(
    vscode.commands.registerCommand("mcpGrid.unregisterMcpServer", async () => {
      if (!isMcpGridRegistered()) {
        vscode.window.showInformationMessage(
          "MCP Grid is not registered as an MCP server."
        );
        return;
      }
      const confirm = await vscode.window.showWarningMessage(
        "Unregister MCP Grid from Cursor's MCP servers? The agent will lose access to MCP Grid tools.",
        "Unregister",
        "Cancel"
      );
      if (confirm === "Unregister") {
        const success = unregisterMcpServer();
        if (success) {
          vscode.window.showInformationMessage(
            "MCP Grid unregistered. Reload the window to apply."
          );
        } else {
          vscode.window.showErrorMessage("Failed to unregister MCP Grid.");
        }
      }
    })
  );

  return disposables;
}
