import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";
import { VCDFileServer } from "../services/vcdFileServer";

/**
 * VCD 波形查看器自定义编辑器提供者
 */
export class VCDViewerEditorProvider
  implements vscode.CustomReadonlyEditorProvider
{
  public static register(
    context: vscode.ExtensionContext,
    vcdFileServer: VCDFileServer,
  ): vscode.Disposable {
    const provider = new VCDViewerEditorProvider(context, vcdFileServer);
    const providerRegistration = vscode.window.registerCustomEditorProvider(
      "ic-coder.vcdViewer",
      provider,
      {
        webviewOptions: {
          retainContextWhenHidden: true,
        },
      },
    );
    return providerRegistration;
  }

  constructor(
    private readonly context: vscode.ExtensionContext,
    private readonly vcdFileServer: VCDFileServer,
  ) {}

  async openCustomDocument(
    uri: vscode.Uri,
    openContext: vscode.CustomDocumentOpenContext,
    token: vscode.CancellationToken,
  ): Promise<vscode.CustomDocument> {
    return {
      uri,
      dispose: () => {},
    };
  }

  async resolveCustomEditor(
    document: vscode.CustomDocument,
    webviewPanel: vscode.WebviewPanel,
    token: vscode.CancellationToken,
  ): Promise<void> {
    webviewPanel.webview.options = {
      enableScripts: true,
      localResourceRoots: [this.context.extensionUri],
    };

    // 使用公共工厂方法创建 VCD 查看器实例
    VCDViewerPanel.createFromWebviewPanel(
      webviewPanel,
      this.context.extensionUri,
      document.uri.fsPath,
      this.vcdFileServer,
    );
  }
}

/**
 * VCD 波形查看器面板 (使用 Surfer)
 */
export class VCDViewerPanel {
  public static currentPanel: VCDViewerPanel | undefined;
  private readonly _panel: vscode.WebviewPanel;
  private readonly _extensionUri: vscode.Uri;
  private _disposables: vscode.Disposable[] = [];
  private _currentVcdPath: string | undefined;
  private _vcdFileServer: VCDFileServer | undefined;

  private constructor(
    panel: vscode.WebviewPanel,
    extensionUri: vscode.Uri,
    vcdFileServer?: VCDFileServer,
  ) {
    this._panel = panel;
    this._extensionUri = extensionUri;
    this._vcdFileServer = vcdFileServer;

    // 设置初始 HTML 内容
    this._panel.webview.html = this._getLoadingHtml();

    // 监听面板关闭事件
    this._panel.onDidDispose(() => this.dispose(), null, this._disposables);

    // 监听来自 webview 的消息
    this._panel.webview.onDidReceiveMessage(
      (message) => {
        console.log("[VCDViewerPanel] 收到消息:", message);
        switch (message.command) {
          case "loadVCD":
            if (message.filePath) {
              this.loadVCDFile(message.filePath);
            }
            break;
          case "loaded":
            // Surfer iframe 加载完成，发送 VCD 文件
            console.log(
              "[VCDViewerPanel] Surfer 已加载，当前 VCD 路径:",
              this._currentVcdPath,
            );
            if (this._currentVcdPath) {
              this.sendVcdToSurfer(this._currentVcdPath);
            }
            break;
        }
      },
      null,
      this._disposables,
    );
  }

  /**
   * 创建或显示 VCD 查看器面板
   */
  public static createOrShow(
    extensionUri: vscode.Uri,
    vcdFilePath?: string,
    vcdFileServer?: VCDFileServer,
  ) {
    // 在当前活动编辑器旁边打开新列
    const column = vscode.ViewColumn.Beside;

    // 如果已经有面板打开，则显示它
    if (VCDViewerPanel.currentPanel) {
      VCDViewerPanel.currentPanel._panel.reveal(column);
      if (vcdFilePath) {
        VCDViewerPanel.currentPanel.loadVCDFile(vcdFilePath);
      }
      return;
    }

    // 创建新面板
    const panel = vscode.window.createWebviewPanel(
      "vcdViewer",
      "VCD 波形查看器",
      column,
      {
        enableScripts: true,
        retainContextWhenHidden: true,
        localResourceRoots: [extensionUri],
      },
    );

    VCDViewerPanel.currentPanel = new VCDViewerPanel(
      panel,
      extensionUri,
      vcdFileServer,
    );

    // 如果提供了 VCD 文件路径，加载它
    if (vcdFilePath) {
      VCDViewerPanel.currentPanel.loadVCDFile(vcdFilePath);
    }
  }

  /**
   * 从已有的 webview panel 创建 VCD 查看器（用于自定义编辑器）
   */
  public static createFromWebviewPanel(
    panel: vscode.WebviewPanel,
    extensionUri: vscode.Uri,
    vcdFilePath: string,
    vcdFileServer?: VCDFileServer,
  ) {
    const viewer = new VCDViewerPanel(panel, extensionUri, vcdFileServer);
    viewer.loadVCDFile(vcdFilePath);
    return viewer;
  }

  /**
   * 加载 VCD 文件
   */
  public loadVCDFile(vcdFilePath: string) {
    try {
      console.log("[VCDViewerPanel] 开始加载 VCD 文件:", vcdFilePath);

      // 检查文件是否存在
      if (!fs.existsSync(vcdFilePath)) {
        vscode.window.showErrorMessage(`VCD 文件不存在: ${vcdFilePath}`);
        return;
      }

      // 保存当前 VCD 路径
      this._currentVcdPath = vcdFilePath;
      console.log("[VCDViewerPanel] VCD 路径已保存:", this._currentVcdPath);

      // 更新面板标题
      const fileName = path.basename(vcdFilePath);
      this._panel.title = `波形查看器 - ${fileName}`;

      // 设置 HTML 内容
      this._panel.webview.html = this._getWebviewContent();
      console.log("[VCDViewerPanel] Webview HTML 已设置");
    } catch (error) {
      vscode.window.showErrorMessage(
        `加载 VCD 文件失败: ${error instanceof Error ? error.message : "未知错误"}`,
      );
    }
  }

  /**
   * 解析 VCD 文件获取根模块及其直接子模块名称
   */
  private parseVcdRootScope(vcdFilePath: string): string[] {
    try {
      // 读取 VCD 文件
      const buffer = fs.readFileSync(vcdFilePath, { encoding: "utf8" });
      const lines = buffer.split("\n");

      const scopeNames: string[] = [];
      let scopeDepth = 0;
      const scopeStack: string[] = [];

      for (const line of lines) {
        const trimmed = line.trim();

        // 遇到 $enddefinitions 就停止解析
        if (trimmed.startsWith("$enddefinitions")) {
          break;
        }

        // 查找 $scope 定义
        const scopeMatch = trimmed.match(/^\$scope\s+(\w+)\s+(\w+)/);
        if (scopeMatch) {
          const scopeType = scopeMatch[1];
          const scopeName = scopeMatch[2];

          // 记录顶层 module (depth = 0)
          if (scopeDepth === 0 && scopeType === "module") {
            scopeStack.push(scopeName);
            console.log("[VCDViewerPanel] 找到顶层作用域:", scopeName);
          }
          // 记录顶层下的直接子模块 (depth = 1)
          else if (scopeDepth === 1 && scopeType === "module") {
            const fullPath = [...scopeStack, scopeName];
            scopeNames.push(fullPath.join("."));
            console.log("[VCDViewerPanel] 找到子模块:", fullPath.join("."));
          }

          scopeDepth++;
        }

        // 遇到 $upscope 减少深度
        if (trimmed.startsWith("$upscope")) {
          scopeDepth--;
          if (scopeDepth === 0) {
            scopeStack.pop();
          }
        }
      }

      return scopeNames;
    } catch (error) {
      console.error("[VCDViewerPanel] 解析 VCD 文件失败:", error);
      return [];
    }
  }

  /**
   * 发送 VCD 文件到 Surfer
   */
  private sendVcdToSurfer(vcdFilePath: string) {
    try {
      console.log("[VCDViewerPanel] 准备发送 VCD 到 Surfer:", vcdFilePath);

      if (!this._vcdFileServer) {
        throw new Error("VCD 文件服务器未初始化");
      }

      // 解析 VCD 文件获取根模块名称
      const scopeNames = this.parseVcdRootScope(vcdFilePath);
      console.log("[VCDViewerPanel] 解析到的作用域名称:", scopeNames);

      // 注册文件到 HTTP 服务器
      const fileId = this._vcdFileServer.registerFile(vcdFilePath);
      const httpUrl = this._vcdFileServer.getFileUrl(fileId);
      const fileName = path.basename(vcdFilePath);

      console.log("[VCDViewerPanel] 文件名:", fileName);
      console.log("[VCDViewerPanel] HTTP URL:", httpUrl);

      // 使用 LoadUrl 命令通过 HTTP 加载文件
      this._panel.webview.postMessage({
        command: "loadVcdUrl",
        url: httpUrl,
        fileName: fileName,
        scopeNames: scopeNames, // 传递解析到的作用域名称
      });

      console.log("[VCDViewerPanel] 已发送 loadVcdUrl 消息到 webview");
    } catch (error) {
      console.error("[VCDViewerPanel] 发送 VCD 数据失败:", error);
      vscode.window.showErrorMessage(
        `发送 VCD 数据失败: ${error instanceof Error ? error.message : "未知错误"}`,
      );
    }
  }

  /**
   * 清理资源
   */
  public dispose() {
    VCDViewerPanel.currentPanel = undefined;

    this._panel.dispose();

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

  /**
   * 获取加载中的 HTML
   */
  private _getLoadingHtml(): string {
    return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>VCD 波形查看器</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            font-family: var(--vscode-font-family);
            color: var(--vscode-foreground);
            background-color: var(--vscode-editor-background);
        }
        .loading {
            text-align: center;
        }
        .spinner {
            border: 4px solid var(--vscode-progressBar-background);
            border-top: 4px solid var(--vscode-progressBar-foreground);
            border-radius: 50%;
            width: 40px;
            height: 40px;
            animation: spin 1s linear infinite;
            margin: 0 auto 20px;
        }
        @keyframes spin {
            0% { transform: rotate(0deg); }
            100% { transform: rotate(360deg); }
        }
    </style>
</head>
<body>
    <div class="loading">
        <div class="spinner"></div>
        <p>正在加载 VCD 波形查看器...</p>
    </div>
</body>
</html>`;
  }

  /**
   * 获取 Webview 的 HTML 内容
   */
  private _getWebviewContent(): string {
    // 获取 surfer 资源 URI
    const surferJsUri = this._panel.webview.asWebviewUri(
      vscode.Uri.joinPath(this._extensionUri, "media", "surfer", "surfer.js"),
    );
    const surferWasmUri = this._panel.webview.asWebviewUri(
      vscode.Uri.joinPath(
        this._extensionUri,
        "media",
        "surfer",
        "surfer_bg.wasm",
      ),
    );
    const integrationJsUri = this._panel.webview.asWebviewUri(
      vscode.Uri.joinPath(
        this._extensionUri,
        "media",
        "surfer",
        "integration.js",
      ),
    );

    return `<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'unsafe-inline'; script-src 'unsafe-inline' 'unsafe-eval' ${this._panel.webview.cspSource}; worker-src blob:; connect-src ${this._panel.webview.cspSource} blob: http://127.0.0.1:*;">
    <title>波形查看器</title>

    <script>
        // 获取 VS Code API（只能调用一次）
        const vscode = acquireVsCodeApi();
        window.vscode = vscode;
        window.surferReady = false;
        window.pendingVcdData = null;

        function on_surfer_error(msg) {
            console.log("Surfer error:", msg);
            document.getElementById("error_message").innerHTML = msg;
            document.getElementById("error_container").style.display = "block";
        }
        window.on_surfer_error = on_surfer_error;

        // 加载 VCD URL 的函数
        function loadVcdUrl(data) {
            try {
                console.log('[Webview] ========== 开始加载 VCD URL ==========');
                console.log('[Webview] URL:', data.url);
                console.log('[Webview] Scope names from VCD:', data.scopeNames);

                // 使用 setTimeout 确保 Surfer 完全准备好
                setTimeout(() => {
                    console.log('[Webview] 通过 postMessage 发送 LoadUrl 命令');

                    // 使用 integration.js 提供的标准 LoadUrl 命令
                    window.postMessage({
                        command: 'LoadUrl',
                        url: data.url
                    }, '*');

                    console.log('[Webview] ✅ 已发送 LoadUrl 命令');

                    // 等待文件加载完成后，自动添加所有信号
                    setTimeout(async () => {
                        try {
                            console.log('[Webview] Attempting to add all signals automatically');

                            // 使用从 VCD 文件解析出来的作用域名称
                            let scopeNamesToTry = [];

                            if (data.scopeNames && data.scopeNames.length > 0) {
                                // 使用解析出来的实际子模块路径（例如 "tb.dut"）
                                scopeNamesToTry = data.scopeNames.map(path => path.split('.'));
                                console.log('[Webview] Using parsed scope names:', scopeNamesToTry);
                            } else {
                                // 回退到常见的根作用域名称
                                scopeNamesToTry = [
                                    ['top'],
                                    ['testbench'],
                                    ['tb'],
                                    ['test'],
                                    ['dut']
                                ];
                                console.log('[Webview] Using fallback scope names');
                            }

                            for (let i = 0; i < scopeNamesToTry.length; i++) {
                                const scopeName = scopeNamesToTry[i];
                                try {
                                    const addScopeMsg = {
                                        "AddScope": [
                                            {
                                                "strs": scopeName,
                                                "id": {"Wellen": i + 1}
                                            },
                                            true  // 递归添加子模块的所有信号
                                        ]
                                    };
                                    window.inject_message(JSON.stringify(addScopeMsg));
                                    console.log('[Webview] Sent AddScope for: ' + scopeName.join('.') + ' (recursive)');
                                } catch (e) {
                                    console.log('[Webview] Failed for scope: ' + scopeName.join('.'), e);
                                }
                            }

                            // 等待信号加载完成后，自动缩放到全部时间范围
                            setTimeout(() => {
                                try {
                                    window.inject_message(JSON.stringify("ZoomToFit"));
                                    console.log('[Webview] Sent ZoomToFit command');
                                } catch (e) {
                                    console.log('[Webview] ZoomToFit failed:', e);
                                }
                            }, 500);

                        } catch (e) {
                            console.error('[Webview] Failed to add signals:', e);
                        }
                    }, 1500);

                }, 100);

            } catch (error) {
                console.error('[Webview] ❌ 加载 VCD 失败:', error);
                on_surfer_error(error.message + '\\n' + error.stack);
            }
        }
        window.loadVcdUrl = loadVcdUrl;
    </script>

    <script type="module">
        console.log('[Webview] 开始初始化 Surfer...');
        import init from '${surferJsUri}';
        await init({module_or_path: '${surferWasmUri}'});
        console.log('[Webview] Surfer WASM 已加载');

        import {WebHandle, inject_message, id_of_name, draw_text_arrow} from '${surferJsUri}';
        window.inject_message = inject_message;
        window.id_of_name = id_of_name;
        window.draw_text_arrow = draw_text_arrow;

        console.log('[Webview] Surfer 函数已导入，inject_message 类型:', typeof window.inject_message);

        // 等待一小段时间确保 Surfer 完全初始化
        await new Promise(resolve => setTimeout(resolve, 100));

        window.surferReady = true;
        console.log('[Webview] Surfer 已完全初始化并准备就绪');

        // 关闭 Surfer 的日志面板（如果打开的话）
        try {
            window.inject_message(JSON.stringify("ToggleLogs"));
            console.log('[Webview] 已发送关闭日志面板命令');
        } catch (e) {
            console.log('[Webview] 关闭日志面板失败:', e);
        }

        // 如果有待处理的 VCD 数据，现在加载它
        if (window.pendingVcdData) {
            console.log('[Webview] 发现待处理的 VCD 数据，立即加载');
            loadVcdUrl(window.pendingVcdData);
            window.pendingVcdData = null;
        } else {
            console.log('[Webview] 没有待处理的 VCD 数据');
        }

        // 通知 VS Code surfer 已加载完成
        console.log('[Webview] 发送 loaded 消息到 VS Code');
        window.vscode.postMessage({ command: 'loaded' });
    </script>

    <style>
        html, body {
            overflow: hidden;
            margin: 0 !important;
            padding: 0 !important;
            height: 100%;
            width: 100%;
            background: var(--vscode-editor-background);
        }

        canvas {
            margin-right: auto;
            margin-left: auto;
            display: block;
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
        }

        #error_container {
            padding: 1em;
            border-radius: 0.5em;
            margin: 0px auto;
            max-width: 980px;
            color: var(--vscode-errorForeground);
            background-color: var(--vscode-inputValidation-errorBackground);
            position: relative;
            height: 90%;
            overflow: scroll;
        }

        #error_message {
            overflow: scroll;
            white-space: break-spaces;
        }
    </style>
</head>
<body>
    <canvas id="the_canvas_id"></canvas>

    <div id="error_container" style="display: none;">
        <h3>❌ Surfer 加载失败</h3>
        <code id="error_message"></code>
    </div>

    <script src="${integrationJsUri}"></script>
    <script>
        register_message_listener();

        console.log('[Webview] 注册 VS Code 消息监听器');
        // 监听来自 VS Code 扩展的消息（使用 vscode API）
        window.addEventListener('message', event => {
            const message = event.data;

            // 检查是否来自 VS Code
            if (message.command === 'loadVcdUrl') {
                console.log('[Webview] 收到 VS Code 消息，命令:', message.command);
                console.log('[Webview] Surfer 就绪状态:', window.surferReady);

                if (window.surferReady) {
                    // Surfer 已就绪，立即加载
                    loadVcdUrl(message);
                } else {
                    // Surfer 未就绪，保存数据等待加载
                    console.log('[Webview] Surfer 未就绪，保存数据待加载');
                    window.pendingVcdData = message;
                }
            }
        }, true); // 使用捕获阶段，优先于 integration.js 的监听器
    </script>
</body>
</html>`;
  }
}
