import * as vscode from "vscode";
import {
  BridgeClient,
  MetricsSummary,
  InstanceInfo,
  ServerInfo,
  RecentCall,
} from "../bridge/client";

/**
 * WebView panel for the main MCP Grid dashboard.
 * Displays real-time overview with metrics, instances, and server status.
 */
export class DashboardPanel {
  public static currentPanel: DashboardPanel | undefined;
  private static readonly _viewType = "mcpGrid.dashboard";

  private readonly _panel: vscode.WebviewPanel;
  private readonly _client: BridgeClient;
  private _refreshInterval: ReturnType<typeof setInterval> | undefined;
  private _disposables: vscode.Disposable[] = [];

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

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

    this._panel.webview.onDidReceiveMessage(
      async (msg) => {
        switch (msg.command) {
          case "refresh":
            await this._updateContent();
            break;
          case "deactivateInstance":
            try {
              await this._client.deactivateInstance(msg.instanceId);
              await this._updateContent();
            } catch (err) {
              vscode.window.showErrorMessage(
                `Failed to deactivate: ${err}`
              );
            }
            break;
        }
      },
      null,
      this._disposables
    );

    // Auto-refresh every 5 seconds
    const pollingInterval = vscode.workspace
      .getConfiguration("mcpGrid")
      .get<number>("pollingInterval", 5000);

    this._refreshInterval = setInterval(
      () => this._updateContent(),
      pollingInterval
    );

    this._updateContent();
  }

  /** Create or show the dashboard panel. */
  static createOrShow(client: BridgeClient): void {
    const column = vscode.window.activeTextEditor
      ? vscode.window.activeTextEditor.viewColumn
      : undefined;

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

    const panel = vscode.window.createWebviewPanel(
      DashboardPanel._viewType,
      "MCP Grid Dashboard",
      column || vscode.ViewColumn.One,
      {
        enableScripts: true,
        retainContextWhenHidden: true,
        localResourceRoots: [],
      }
    );

    DashboardPanel.currentPanel = new DashboardPanel(panel, client);
  }

  dispose(): void {
    DashboardPanel.currentPanel = undefined;

    if (this._refreshInterval) {
      clearInterval(this._refreshInterval);
    }

    this._panel.dispose();
    while (this._disposables.length) {
      const x = this._disposables.pop();
      if (x) {
        x.dispose();
      }
    }
  }

  private async _updateContent(): Promise<void> {
    let metrics: MetricsSummary | null = null;
    let instances: InstanceInfo[] = [];
    let servers: ServerInfo[] = [];
    let recentCalls: RecentCall[] = [];
    let bridgeAlive = false;

    try {
      bridgeAlive = await this._client.isAlive();
      if (bridgeAlive) {
        [metrics, instances, servers, recentCalls] = await Promise.all([
          this._client.getMetrics(),
          this._client.listInstances(),
          this._client.listServers(),
          this._client.getRecentCalls(10),
        ]);
      }
    } catch {
      bridgeAlive = false;
    }

    this._panel.webview.html = this._getHtml(
      bridgeAlive,
      metrics,
      instances,
      servers,
      recentCalls
    );
  }

  /** Escape HTML special characters to prevent XSS. */
  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(
    alive: boolean,
    metrics: MetricsSummary | null,
    instances: InstanceInfo[],
    servers: ServerInfo[],
    recentCalls: RecentCall[]
  ): string {
    const statusBadge = alive
      ? '<span class="badge badge-green">Connected</span>'
      : '<span class="badge badge-red">Disconnected</span>';

    const totalCalls = metrics?.total_calls ?? 0;
    const successfulCalls = metrics?.successful_calls ?? 0;
    const failedCalls = metrics?.failed_calls ?? 0;
    const avgLatency = metrics?.avg_latency_ms ?? 0;

    const metricsHtml = metrics
      ? `
      <div class="metrics-grid">
        <div class="metric-card">
          <div class="metric-value">${totalCalls}</div>
          <div class="metric-label">Total Calls</div>
        </div>
        <div class="metric-card">
          <div class="metric-value">${totalCalls > 0 ? ((successfulCalls / totalCalls) * 100).toFixed(1) : "0.0"}%</div>
          <div class="metric-label">Success Rate</div>
        </div>
        <div class="metric-card">
          <div class="metric-value green">${successfulCalls}</div>
          <div class="metric-label">Successful</div>
        </div>
        <div class="metric-card">
          <div class="metric-value red">${failedCalls}</div>
          <div class="metric-label">Failed</div>
        </div>
        <div class="metric-card">
          <div class="metric-value">${avgLatency.toFixed(0)}ms</div>
          <div class="metric-label">Avg Latency</div>
        </div>
        <div class="metric-card">
          <div class="metric-value">${instances.length}</div>
          <div class="metric-label">Active Instances</div>
        </div>
      </div>`
      : '<p class="muted">No metrics available</p>';

    const instanceRows = instances
      .map(
        (i) => `
        <tr>
          <td><code>${this._esc(i.instance_id.substring(0, 12))}</code></td>
          <td>${this._esc(i.server_id)}</td>
          <td><span class="badge badge-${(i.state === "running" || i.state === "active") ? "green" : "yellow"}">${this._esc(i.state)}</span></td>
          <td>${i.total_tool_calls}</td>
          <td>${i.tools.length} tools</td>
          <td><button class="btn btn-sm btn-danger" onclick="deactivate('${this._esc(i.instance_id)}')">Stop</button></td>
        </tr>`
      )
      .join("");

    const serverRows = servers
      .map(
        (s) => `
        <tr>
          <td>${this._esc(s.name || s.id)}</td>
          <td>${this._esc(s.category)}</td>
          <td>${this._esc(s.transport)}</td>
          <td><span class="badge badge-${s.enabled ? "green" : "red"}">${s.enabled ? "Enabled" : "Disabled"}</span></td>
        </tr>`
      )
      .join("");

    const callRows = recentCalls
      .map(
        (c) => `
        <tr>
          <td>${this._esc(c.tool_name || "unknown")}</td>
          <td>${this._esc(c.server_id || "?")}</td>
          <td><span class="badge badge-${c.success ? "green" : "red"}">${c.success ? "OK" : "Fail"}</span></td>
          <td>${(c.latency_ms ?? 0).toFixed(0)}ms</td>
        </tr>`
      )
      .join("");

    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>MCP Grid Dashboard</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);
    }
    body {
      font-family: var(--vscode-font-family);
      font-size: var(--vscode-font-size);
      color: var(--fg);
      background: var(--bg);
      padding: 16px;
      margin: 0;
    }
    h1 { font-size: 1.6em; margin-bottom: 4px; }
    h2 { font-size: 1.2em; margin-top: 24px; margin-bottom: 8px; border-bottom: 1px solid var(--border); padding-bottom: 4px; }
    .header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; }
    .header h1 { margin: 0; }
    .badge { padding: 2px 8px; border-radius: 10px; font-size: 0.85em; font-weight: 600; }
    .badge-green { background: #2ea04370; color: #3fb950; }
    .badge-red { background: #f8514970; color: #f85149; }
    .badge-yellow { background: #d2992270; color: #d29922; }
    .metrics-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 12px; margin: 12px 0; }
    .metric-card {
      background: var(--card-bg);
      border: 1px solid var(--border);
      border-radius: 8px;
      padding: 16px;
      text-align: center;
    }
    .metric-value { font-size: 2em; font-weight: 700; color: var(--accent); }
    .metric-value.green { color: #3fb950; }
    .metric-value.red { color: #f85149; }
    .metric-label { font-size: 0.85em; color: var(--muted); margin-top: 4px; }
    table { width: 100%; border-collapse: collapse; margin: 8px 0; }
    th, td { text-align: left; padding: 6px 10px; border-bottom: 1px solid var(--border); }
    th { font-weight: 600; color: var(--muted); font-size: 0.9em; }
    code { font-family: var(--vscode-editor-font-family); font-size: 0.9em; }
    .btn { cursor: pointer; border: none; border-radius: 4px; padding: 4px 10px; font-size: 0.85em; }
    .btn-sm { padding: 2px 8px; }
    .btn-danger { background: #f8514940; color: #f85149; }
    .btn-danger:hover { background: #f8514970; }
    .btn-primary { background: var(--vscode-button-background); color: var(--vscode-button-foreground); }
    .btn-primary:hover { background: var(--vscode-button-hoverBackground); }
    .toolbar { display: flex; gap: 8px; margin-bottom: 12px; }
    .muted { color: var(--muted); }
    .empty { text-align: center; padding: 20px; color: var(--muted); }
  </style>
</head>
<body>
  <div class="header">
    <h1>MCP Grid</h1>
    ${statusBadge}
    <button class="btn btn-primary" onclick="refresh()">Refresh</button>
  </div>

  ${metricsHtml}

  <h2>Active Instances (${instances.length})</h2>
  ${
    instances.length > 0
      ? `<table><thead><tr><th>ID</th><th>Server</th><th>State</th><th>Calls</th><th>Tools</th><th></th></tr></thead><tbody>${instanceRows}</tbody></table>`
      : '<p class="empty">No active instances</p>'
  }

  <h2>Registered Servers (${servers.length})</h2>
  ${
    servers.length > 0
      ? `<table><thead><tr><th>Name</th><th>Category</th><th>Transport</th><th>Status</th></tr></thead><tbody>${serverRows}</tbody></table>`
      : '<p class="empty">No servers registered</p>'
  }

  <h2>Recent Calls</h2>
  ${
    recentCalls.length > 0
      ? `<table><thead><tr><th>Tool</th><th>Server</th><th>Status</th><th>Latency</th></tr></thead><tbody>${callRows}</tbody></table>`
      : '<p class="empty">No recent calls</p>'
  }

  <script>
    const vscode = acquireVsCodeApi();
    function refresh() { vscode.postMessage({ command: 'refresh' }); }
    function deactivate(id) { vscode.postMessage({ command: 'deactivateInstance', instanceId: id }); }
  </script>
</body>
</html>`;
  }
}
