import * as vscode from "vscode";
import { BridgeClient } from "../bridge/client";

/**
 * WebView panel for adding a new MCP server.
 *
 * Supports three modes:
 * 1. OpenAPI/Swagger -- import from spec URL or file
 * 2. Manual -- configure command, transport, category, etc.
 * 3. WebSocket -- connect to an enterprise AI platform endpoint
 */
export class AddServerPanel {
  public static currentPanel: AddServerPanel | undefined;
  private static readonly _viewType = "mcpGrid.addServer";

  private readonly _panel: vscode.WebviewPanel;
  private readonly _client: BridgeClient;
  private _disposables: vscode.Disposable[] = [];

  private constructor(
    panel: vscode.WebviewPanel,
    client: BridgeClient,
    private readonly _initialTab: string
  ) {
    this._panel = panel;
    this._client = client;

    this._panel.onDidDispose(() => this.dispose(), null, this._disposables);

    this._panel.webview.onDidReceiveMessage(
      async (msg) => {
        switch (msg.command) {
          case "addManualServer":
            await this._handleManualServer(msg);
            break;
          case "addOpenAPIServer":
            await this._handleOpenAPIServer(msg);
            break;
          case "addWebSocketServer":
            await this._handleWebSocketServer(msg);
            break;
        }
      },
      null,
      this._disposables
    );

    this._panel.webview.html = this._getHtml();
  }

  static createOrShow(
    client: BridgeClient,
    initialTab: string = "manual"
  ): void {
    const column = vscode.window.activeTextEditor
      ? vscode.window.activeTextEditor.viewColumn
      : undefined;

    if (AddServerPanel.currentPanel) {
      AddServerPanel.currentPanel._panel.reveal(column);
      return;
    }

    const panel = vscode.window.createWebviewPanel(
      AddServerPanel._viewType,
      "Add MCP Server",
      column || vscode.ViewColumn.One,
      {
        enableScripts: true,
        retainContextWhenHidden: false,
        localResourceRoots: [],
      }
    );

    AddServerPanel.currentPanel = new AddServerPanel(panel, client, initialTab);
  }

  dispose(): void {
    AddServerPanel.currentPanel = undefined;
    this._panel.dispose();
    while (this._disposables.length) {
      const x = this._disposables.pop();
      if (x) {
        x.dispose();
      }
    }
  }

  private async _handleManualServer(msg: Record<string, string>) {
    try {
      await this._client.registerServer({
        id: msg.id,
        name: msg.name || msg.id,
        command: msg.command,
        args: [],
        env: {},
        transport: msg.transport || "stdio",
        category: msg.category || "custom",
        source: "user",
        enabled: true,
      });
      this._panel.webview.postMessage({
        command: "success",
        text: `Server "${msg.name || msg.id}" added successfully!`,
      });
    } catch (err) {
      this._panel.webview.postMessage({
        command: "error",
        text: `Failed to add server: ${err}`,
      });
    }
  }

  private async _handleOpenAPIServer(msg: Record<string, string>) {
    // OpenAPI import is done via the agent tool, but we can give helpful guidance
    this._panel.webview.postMessage({
      command: "success",
      text: `OpenAPI spec noted. Use the agent tool: import_openapi_spec('${msg.specUrl}'${msg.pluginName ? `, '${msg.pluginName}'` : ""}) to complete the import.`,
    });
  }

  private async _handleWebSocketServer(msg: Record<string, string>) {
    try {
      const configOptions = [];
      if (msg.authUrl) {
        configOptions.push({
          name: "auth_url",
          type: "string",
          description: "Authentication URL for the platform",
          default: msg.authUrl,
          required: true,
        });
      }
      configOptions.push(
        {
          name: "ws_endpoint",
          type: "string",
          description: "WebSocket endpoint URL",
          default: msg.wsEndpoint || "",
          required: true,
        },
        {
          name: "auth_mode",
          type: "enum",
          description: "Authentication mode",
          default: msg.authMode || "token",
          required: true,
          enum_values: ["token", "browser", "oauth2", "api_key"],
        }
      );

      await this._client.registerServer({
        id: msg.id,
        name: msg.name || msg.id,
        description: msg.description || "WebSocket-based MCP server",
        command: msg.command || "mcp-grid",
        args: ["--ws-bridge"],
        env: {},
        transport: "http",
        category: msg.category || "ai-ml",
        source: "user",
        enabled: true,
        configurable_options: configOptions,
      });
      this._panel.webview.postMessage({
        command: "success",
        text: `WebSocket server "${msg.name || msg.id}" configured successfully!`,
      });
    } catch (err) {
      this._panel.webview.postMessage({
        command: "error",
        text: `Failed to add WebSocket server: ${err}`,
      });
    }
  }

  private _esc(value: unknown): string {
    return String(value ?? "")
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#39;");
  }

  private _getHtml(): string {
    const initialTab = this._esc(this._initialTab);

    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline';">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Add MCP Server</title>
  <style>
    :root {
      --bg: var(--vscode-editor-background);
      --fg: var(--vscode-editor-foreground);
      --border: var(--vscode-widget-border);
      --card-bg: var(--vscode-editorWidget-background);
      --accent: var(--vscode-textLink-foreground);
      --muted: var(--vscode-descriptionForeground);
      --input-bg: var(--vscode-input-background);
      --input-border: var(--vscode-input-border);
      --input-fg: var(--vscode-input-foreground);
      --btn-bg: var(--vscode-button-background);
      --btn-fg: var(--vscode-button-foreground);
      --btn-hover: var(--vscode-button-hoverBackground);
      --error: #f85149;
      --success: #3fb950;
    }
    body {
      font-family: var(--vscode-font-family);
      font-size: var(--vscode-font-size);
      color: var(--fg);
      background: var(--bg);
      padding: 20px;
      margin: 0;
      max-width: 680px;
    }
    h1 { font-size: 1.5em; margin-bottom: 4px; }
    .subtitle { color: var(--muted); margin-bottom: 20px; font-size: 0.9em; }
    .tabs {
      display: flex;
      gap: 0;
      border-bottom: 1px solid var(--border);
      margin-bottom: 20px;
    }
    .tab {
      padding: 10px 20px;
      cursor: pointer;
      border: none;
      background: none;
      color: var(--muted);
      font-size: 0.95em;
      font-weight: 600;
      border-bottom: 2px solid transparent;
      transition: all 0.15s;
    }
    .tab:hover { color: var(--fg); }
    .tab.active { color: var(--accent); border-bottom-color: var(--accent); }
    .tab-content { display: none; }
    .tab-content.active { display: block; }
    .form-group { margin-bottom: 16px; }
    label {
      display: block;
      font-weight: 600;
      margin-bottom: 4px;
      font-size: 0.9em;
    }
    .hint { font-size: 0.8em; color: var(--muted); margin-top: 2px; }
    input, select, textarea {
      width: 100%;
      padding: 8px 10px;
      border: 1px solid var(--input-border);
      background: var(--input-bg);
      color: var(--input-fg);
      border-radius: 4px;
      font-family: inherit;
      font-size: 0.95em;
      box-sizing: border-box;
    }
    textarea { resize: vertical; min-height: 80px; }
    input:focus, select:focus, textarea:focus {
      outline: none;
      border-color: var(--accent);
    }
    .btn {
      display: inline-flex;
      align-items: center;
      gap: 6px;
      padding: 8px 20px;
      border-radius: 4px;
      font-weight: 600;
      font-size: 0.95em;
      border: none;
      cursor: pointer;
      background: var(--btn-bg);
      color: var(--btn-fg);
    }
    .btn:hover { background: var(--btn-hover); }
    .btn-row { display: flex; gap: 10px; margin-top: 20px; }
    .message {
      padding: 10px 14px;
      border-radius: 6px;
      margin-bottom: 16px;
      font-size: 0.9em;
      display: none;
    }
    .message.success { display: block; background: rgba(63,185,80,0.15); color: var(--success); border: 1px solid rgba(63,185,80,0.3); }
    .message.error { display: block; background: rgba(248,81,73,0.15); color: var(--error); border: 1px solid rgba(248,81,73,0.3); }
    .required::after { content: " *"; color: var(--error); }
    fieldset {
      border: 1px solid var(--border);
      border-radius: 6px;
      padding: 16px;
      margin-bottom: 16px;
    }
    legend { font-weight: 600; font-size: 0.95em; padding: 0 8px; }
    .checkbox-row {
      display: flex;
      align-items: center;
      gap: 8px;
      margin-bottom: 8px;
    }
    .checkbox-row input[type="checkbox"] { width: auto; }
  </style>
</head>
<body>
  <h1>Add MCP Server</h1>
  <p class="subtitle">Configure a new MCP server to add to your workspace.</p>

  <div id="msg" class="message"></div>

  <div class="tabs">
    <button class="tab" data-tab="manual" id="tab-manual">Manual</button>
    <button class="tab" data-tab="openapi" id="tab-openapi">OpenAPI / Swagger</button>
    <button class="tab" data-tab="websocket" id="tab-websocket">WebSocket / Platform</button>
  </div>

  <!-- Manual Tab -->
  <div class="tab-content" id="content-manual">
    <div class="form-group">
      <label class="required">Server ID</label>
      <input type="text" id="m-id" placeholder="my-custom-server">
      <div class="hint">Unique identifier (lowercase, hyphens allowed)</div>
    </div>
    <div class="form-group">
      <label>Display Name</label>
      <input type="text" id="m-name" placeholder="My Custom Server">
    </div>
    <div class="form-group">
      <label class="required">Command</label>
      <input type="text" id="m-command" placeholder="npx @org/my-mcp-server  or  uvx my-mcp-server">
      <div class="hint">The command that starts the MCP server process</div>
    </div>
    <div class="form-group">
      <label>Transport</label>
      <select id="m-transport">
        <option value="stdio" selected>STDIO (recommended)</option>
        <option value="http">HTTP</option>
        <option value="sse">SSE</option>
      </select>
    </div>
    <div class="form-group">
      <label>Category</label>
      <select id="m-category">
        <option value="custom">Custom</option>
        <option value="browser-automation">Browser Automation</option>
        <option value="data-analytics">Data & Analytics</option>
        <option value="development">Development</option>
        <option value="ai-ml">AI / ML</option>
        <option value="communication">Communication</option>
        <option value="file-systems">File Systems</option>
        <option value="search-web">Search & Web</option>
        <option value="utilities">Utilities</option>
      </select>
    </div>
    <div class="btn-row">
      <button class="btn" onclick="submitManual()">Add Server</button>
    </div>
  </div>

  <!-- OpenAPI Tab -->
  <div class="tab-content" id="content-openapi">
    <div class="form-group">
      <label class="required">OpenAPI / Swagger Spec</label>
      <input type="text" id="o-spec" placeholder="https://api.example.com/openapi.json  or  /path/to/spec.yaml">
      <div class="hint">URL or local path to an OpenAPI 3.x or Swagger 2.x specification</div>
    </div>
    <div class="form-group">
      <label>Plugin Name</label>
      <input type="text" id="o-name" placeholder="my-api (auto-detected from spec if empty)">
    </div>
    <fieldset>
      <legend>Authentication</legend>
      <div class="form-group">
        <label>Auth Mode</label>
        <select id="o-auth">
          <option value="none">None</option>
          <option value="api_key">API Key</option>
          <option value="bearer">Bearer Token</option>
          <option value="oauth2">OAuth2</option>
          <option value="basic">Basic Auth</option>
        </select>
      </div>
      <div class="form-group">
        <label>API Key / Token (if applicable)</label>
        <input type="password" id="o-token" placeholder="Will be stored securely via VS Code SecretStorage">
      </div>
    </fieldset>
    <div class="btn-row">
      <button class="btn" onclick="submitOpenAPI()">Import Spec</button>
    </div>
  </div>

  <!-- WebSocket / Platform Tab -->
  <div class="tab-content" id="content-websocket">
    <p class="hint" style="margin-bottom: 16px;">
      Connect to an enterprise AI platform that exposes workflow chains via WebSocket.
      Configure authentication and endpoint details below.
    </p>
    <div class="form-group">
      <label class="required">Server ID</label>
      <input type="text" id="w-id" placeholder="my-platform-ws">
    </div>
    <div class="form-group">
      <label>Display Name</label>
      <input type="text" id="w-name" placeholder="Enterprise AI Platform">
    </div>
    <fieldset>
      <legend>Authentication</legend>
      <div class="form-group">
        <label class="required">Platform Authentication URL</label>
        <input type="text" id="w-auth-url" placeholder="https://login.platform.example.com/authorize">
        <div class="hint">SSO / OAuth2 login page URL for the platform</div>
      </div>
      <div class="form-group">
        <label>Auth Mode</label>
        <select id="w-auth-mode">
          <option value="browser">Browser-based SSO (recommended)</option>
          <option value="token">Token / API Key</option>
          <option value="oauth2">OAuth2 Client Credentials</option>
          <option value="api_key">API Key Header</option>
        </select>
      </div>
    </fieldset>
    <fieldset>
      <legend>WebSocket Endpoint</legend>
      <div class="form-group">
        <label class="required">WebSocket URL</label>
        <input type="text" id="w-ws-endpoint" placeholder="wss://platform.example.com/ws/agent">
        <div class="hint">The WebSocket endpoint for real-time workflow execution</div>
      </div>
    </fieldset>
    <fieldset>
      <legend>API Endpoints (optional)</legend>
      <div class="form-group">
        <label>REST API Base URL</label>
        <input type="text" id="w-api-base" placeholder="https://platform.example.com/api/v2">
        <div class="hint">If the platform has REST APIs for workflow listing, etc.</div>
      </div>
      <div class="form-group">
        <label>Swagger / OpenAPI Spec URL</label>
        <input type="text" id="w-swagger" placeholder="https://platform.example.com/swagger-ui.html">
      </div>
    </fieldset>
    <div class="form-group">
      <label>Category</label>
      <select id="w-category">
        <option value="ai-ml" selected>AI / ML</option>
        <option value="development">Development</option>
        <option value="custom">Custom</option>
      </select>
    </div>
    <div class="btn-row">
      <button class="btn" onclick="submitWebSocket()">Add Platform Server</button>
    </div>
  </div>

  <script>
    const vscode = acquireVsCodeApi();

    // Tab switching
    const tabs = document.querySelectorAll('.tab');
    const contents = document.querySelectorAll('.tab-content');
    function switchTab(tabId) {
      tabs.forEach(t => t.classList.toggle('active', t.dataset.tab === tabId));
      contents.forEach(c => c.classList.toggle('active', c.id === 'content-' + tabId));
    }
    tabs.forEach(t => t.addEventListener('click', () => switchTab(t.dataset.tab)));
    switchTab('${initialTab}');

    // Message handling
    window.addEventListener('message', e => {
      const msg = e.data;
      const el = document.getElementById('msg');
      if (msg.command === 'success') {
        el.className = 'message success';
        el.textContent = msg.text;
      } else if (msg.command === 'error') {
        el.className = 'message error';
        el.textContent = msg.text;
      }
    });

    function submitManual() {
      const id = document.getElementById('m-id').value.trim();
      const command = document.getElementById('m-command').value.trim();
      if (!id || !command) {
        document.getElementById('msg').className = 'message error';
        document.getElementById('msg').textContent = 'Server ID and Command are required.';
        return;
      }
      vscode.postMessage({
        command: 'addManualServer',
        id,
        name: document.getElementById('m-name').value.trim(),
        command,
        transport: document.getElementById('m-transport').value,
        category: document.getElementById('m-category').value,
      });
    }

    function submitOpenAPI() {
      const specUrl = document.getElementById('o-spec').value.trim();
      if (!specUrl) {
        document.getElementById('msg').className = 'message error';
        document.getElementById('msg').textContent = 'OpenAPI spec URL or path is required.';
        return;
      }
      vscode.postMessage({
        command: 'addOpenAPIServer',
        specUrl,
        pluginName: document.getElementById('o-name').value.trim(),
        authMode: document.getElementById('o-auth').value,
        token: document.getElementById('o-token').value,
      });
    }

    function submitWebSocket() {
      const id = document.getElementById('w-id').value.trim();
      const wsEndpoint = document.getElementById('w-ws-endpoint').value.trim();
      if (!id || !wsEndpoint) {
        document.getElementById('msg').className = 'message error';
        document.getElementById('msg').textContent = 'Server ID and WebSocket URL are required.';
        return;
      }
      vscode.postMessage({
        command: 'addWebSocketServer',
        id,
        name: document.getElementById('w-name').value.trim(),
        authUrl: document.getElementById('w-auth-url').value.trim(),
        authMode: document.getElementById('w-auth-mode').value,
        wsEndpoint,
        apiBase: document.getElementById('w-api-base').value.trim(),
        swagger: document.getElementById('w-swagger').value.trim(),
        category: document.getElementById('w-category').value,
      });
    }
  </script>
</body>
</html>`;
  }
}
