import * as http from "http";
import * as fs from "fs";
import * as path from "path";
import * as vscode from "vscode";

/**
 * VCD 文件 HTTP 服务器
 * 用于为 波形查看器提供 VCD 文件访问
 */
export class VCDFileServer {
  private server: http.Server | null = null;
  private port: number = 0;
  private vcdFiles: Map<string, string> = new Map(); // fileId -> filePath
  private extensionUri: vscode.Uri;

  constructor(extensionUri: vscode.Uri) {
    this.extensionUri = extensionUri;
  }

  /**
   * 启动服务器
   */
  public async start(): Promise<number> {
    if (this.server) {
      return this.port;
    }

    return new Promise((resolve, reject) => {
      this.server = http.createServer((req, res) => {
        this.handleRequest(req, res);
      });

      // 监听随机端口
      this.server.listen(0, "127.0.0.1", () => {
        const address = this.server!.address();
        if (address && typeof address === "object") {
          this.port = address.port;
          console.log(`[VCDFileServer] 服务器已启动，端口: ${this.port}`);
          resolve(this.port);
        } else {
          reject(new Error("无法获取服务器端口"));
        }
      });

      this.server.on("error", (error) => {
        console.error("[VCDFileServer] 服务器错误:", error);
        reject(error);
      });
    });
  }

  /**
   * 停止服务器
   */
  public stop(): void {
    if (this.server) {
      this.server.close();
      this.server = null;
      this.port = 0;
      this.vcdFiles.clear();
      console.log("[VCDFileServer] 服务器已停止");
    }
  }

  /**
   * 注册 VCD 文件
   */
  public registerFile(filePath: string): string {
    const fileId = this.generateFileId(filePath);
    this.vcdFiles.set(fileId, filePath);
    console.log(`[VCDFileServer] 注册文件: ${fileId} -> ${filePath}`);
    return fileId;
  }

  /**
   * 获取文件 URL
   */
  public getFileUrl(fileId: string): string {
    return `http://127.0.0.1:${this.port}/vcd/${fileId}`;
  }

  /**
   * 获取波形查看器 URL
   */
  public getViewerUrl(fileId: string): string {
    return `http://127.0.0.1:${this.port}/viewer/${fileId}`;
  }

  /**
   * 生成文件 ID
   */
  private generateFileId(filePath: string): string {
    const timestamp = Date.now();
    const fileName = path.basename(filePath);
    return `${timestamp}-${fileName}`;
  }

  /**
   * 处理 HTTP 请求
   */
  private handleRequest(
    req: http.IncomingMessage,
    res: http.ServerResponse,
  ): void {
    const url = req.url || "";
    console.log(`[VCDFileServer] 收到请求: ${url}`);

    // 设置 CORS 头
    res.setHeader("Access-Control-Allow-Origin", "*");
    res.setHeader("Access-Control-Allow-Methods", "GET, OPTIONS");
    res.setHeader("Access-Control-Allow-Headers", "Content-Type");

    // 处理 OPTIONS 请求
    if (req.method === "OPTIONS") {
      res.writeHead(200);
      res.end();
      return;
    }

    // 路由处理
    if (url.startsWith("/viewer/")) {
      this.handleViewerRequest(url, res);
    } else if (url.startsWith("/vcd/")) {
      this.handleVcdFileRequest(url, res);
    } else if (url.startsWith("/static/")) {
      this.handleStaticFileRequest(url, res);
    } else {
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("Not Found");
    }
  }

  /**
   * 处理查看器页面请求
   */
  private handleViewerRequest(url: string, res: http.ServerResponse): void {
    const match = url.match(/^\/viewer\/(.+)$/);
    if (!match) {
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("Not Found");
      return;
    }

    const fileId = match[1];
    const filePath = this.vcdFiles.get(fileId);

    if (!filePath) {
      console.error(`[VCDFileServer] 文件 ID 不存在: ${fileId}`);
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("File Not Found");
      return;
    }

    // 生成 HTML 页面
    const html = this.generateViewerHtml(fileId, filePath);
    res.writeHead(200, {
      "Content-Type": "text/html; charset=utf-8",
      "Content-Length": Buffer.byteLength(html),
    });
    res.end(html);
  }

  /**
   * 处理 VCD 文件请求
   */
  private handleVcdFileRequest(url: string, res: http.ServerResponse): void {
    const match = url.match(/^\/vcd\/(.+)$/);
    if (!match) {
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("Not Found");
      return;
    }

    const fileId = match[1];
    const filePath = this.vcdFiles.get(fileId);

    if (!filePath) {
      console.error(`[VCDFileServer] 文件 ID 不存在: ${fileId}`);
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("File Not Found");
      return;
    }

    // 检查文件是否存在
    if (!fs.existsSync(filePath)) {
      console.error(`[VCDFileServer] 文件不存在: ${filePath}`);
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("File Not Found");
      return;
    }

    // 读取并发送文件
    try {
      const fileContent = fs.readFileSync(filePath);
      res.writeHead(200, {
        "Content-Type": "text/plain",
        "Content-Length": fileContent.length,
      });
      res.end(fileContent);
      console.log(`[VCDFileServer] 成功发送文件: ${filePath}`);
    } catch (error) {
      console.error(`[VCDFileServer] 读取文件失败:`, error);
      res.writeHead(500, { "Content-Type": "text/plain" });
      res.end("Internal Server Error");
    }
  }

  /**
   * 处理静态文件请求（Surfer 资源）
   */
  private handleStaticFileRequest(url: string, res: http.ServerResponse): void {
    const match = url.match(/^\/static\/(.+)$/);
    if (!match) {
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("Not Found");
      return;
    }

    const fileName = match[1];
    const filePath = path.join(
      this.extensionUri.fsPath,
      "media",
      "surfer",
      fileName,
    );

    if (!fs.existsSync(filePath)) {
      console.error(`[VCDFileServer] 静态文件不存在: ${filePath}`);
      res.writeHead(404, { "Content-Type": "text/plain" });
      res.end("File Not Found");
      return;
    }

    try {
      const fileContent = fs.readFileSync(filePath);
      const contentType = this.getContentType(fileName);
      res.writeHead(200, {
        "Content-Type": contentType,
        "Content-Length": fileContent.length,
      });
      res.end(fileContent);
    } catch (error) {
      console.error(`[VCDFileServer] 读取静态文件失败:`, error);
      res.writeHead(500, { "Content-Type": "text/plain" });
      res.end("Internal Server Error");
    }
  }

  /**
   * 获取文件的 Content-Type
   */
  private getContentType(fileName: string): string {
    const ext = path.extname(fileName).toLowerCase();
    const contentTypes: { [key: string]: string } = {
      ".js": "application/javascript",
      ".wasm": "application/wasm",
      ".html": "text/html",
      ".css": "text/css",
    };
    return contentTypes[ext] || "application/octet-stream";
  }

  /**
   * 解析 VCD 文件获取根模块及其直接子模块名称
   */
  private parseVcdRootScope(vcdFilePath: string): string[] {
    try {
      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();

        if (trimmed.startsWith("$enddefinitions")) {
          break;
        }

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

          if (scopeDepth === 0 && scopeType === "module") {
            scopeStack.push(scopeName);
          } else if (scopeDepth === 1 && scopeType === "module") {
            const fullPath = [...scopeStack, scopeName];
            scopeNames.push(fullPath.join("."));
          }

          scopeDepth++;
        }

        if (trimmed.startsWith("$upscope")) {
          scopeDepth--;
          if (scopeDepth === 0) {
            scopeStack.pop();
          }
        }
      }

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

  /**
   * 生成波形查看器 HTML 页面
   */
  private generateViewerHtml(fileId: string, vcdFilePath: string): string {
    const vcdUrl = this.getFileUrl(fileId);
    const fileName = path.basename(vcdFilePath);
    const scopeNames = this.parseVcdRootScope(vcdFilePath);
    const scopeNamesJson = JSON.stringify(scopeNames);

    const htmlPart1 = this.getHtmlPart1(fileName);
    const htmlPart2 = this.getHtmlPart2(vcdUrl, scopeNamesJson);
    const htmlPart3 = this.getHtmlPart3();

    return htmlPart1 + htmlPart2 + htmlPart3;
  }

  private getHtmlPart1(fileName: string): string {
    return `<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no">
    <title>波形查看器 - ${fileName}</title>
    <script>
        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;
    </script>
    <script type="module">
        console.log('[Browser] 开始初始化 Surfer...');
        import init from '/static/surfer.js';
        await init({module_or_path: '/static/surfer_bg.wasm'});
        console.log('[Browser] Surfer WASM 已加载');

        import {WebHandle, inject_message, id_of_name, draw_text_arrow} from '/static/surfer.js';
        window.inject_message = inject_message;
        window.id_of_name = id_of_name;
        window.draw_text_arrow = draw_text_arrow;

        await new Promise(resolve => setTimeout(resolve, 100));
        window.surferReady = true;
        console.log('[Browser] Surfer 已完全初始化并准备就绪');

        try {
            window.inject_message(JSON.stringify("ToggleLogs"));
            console.log('[Browser] 已发送关闭日志面板命令');
        } catch (e) {
            console.log('[Browser] 关闭日志面板失败:', e);
        }

        if (window.pendingVcdData) {
            console.log('[Browser] 发现待处理的 VCD 数据，立即加载');
            loadVcdUrl(window.pendingVcdData);
            window.pendingVcdData = null;
        }
    </script>`;
  }

  private getHtmlPart2(vcdUrl: string, scopeNamesJson: string): string {
    return `
    <script>
        function loadVcdUrl(data) {
            try {
                console.log('[Browser] ========== 开始加载 VCD URL ==========');
                console.log('[Browser] URL:', data.url);
                console.log('[Browser] Scope names from VCD:', data.scopeNames);

                setTimeout(() => {
                    console.log('[Browser] 通过 postMessage 发送 LoadUrl 命令');
                    window.postMessage({
                        command: 'LoadUrl',
                        url: data.url
                    }, '*');
                    console.log('[Browser] ✅ 已发送 LoadUrl 命令');

                    setTimeout(async () => {
                        try {
                            console.log('[Browser] 尝试自动添加所有信号');
                            let scopeNamesToTry = [];

                            if (data.scopeNames && data.scopeNames.length > 0) {
                                scopeNamesToTry = data.scopeNames.map(path => path.split('.'));
                                console.log('[Browser] 使用解析的作用域名称:', scopeNamesToTry);
                            } else {
                                scopeNamesToTry = [['top'], ['testbench'], ['tb'], ['test'], ['dut']];
                                console.log('[Browser] 使用回退作用域名称');
                            }

                            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('[Browser] 已发送 AddScope: ' + scopeName.join('.'));
                                } catch (e) {
                                    console.log('[Browser] AddScope 失败: ' + scopeName.join('.'), e);
                                }
                            }

                            setTimeout(() => {
                                try {
                                    window.inject_message(JSON.stringify("ZoomToFit"));
                                    console.log('[Browser] 已发送 ZoomToFit 命令');
                                } catch (e) {
                                    console.log('[Browser] ZoomToFit 失败:', e);
                                }
                            }, 500);
                        } catch (e) {
                            console.error('[Browser] 添加信号失败:', e);
                        }
                    }, 1500);
                }, 100);
            } catch (error) {
                console.error('[Browser] ❌ 加载 VCD 失败:', error);
                on_surfer_error(error.message + '\\n' + error.stack);
            }
        }
        window.loadVcdUrl = loadVcdUrl;

        // 页面加载完成后自动加载 VCD
        window.addEventListener('load', () => {
            const vcdData = {
                url: '${vcdUrl}',
                scopeNames: ${scopeNamesJson}
            };
            if (window.surferReady) {
                loadVcdUrl(vcdData);
            } else {
                window.pendingVcdData = vcdData;
            }
        });
    </script>`;
  }

  private getHtmlPart3(): string {
    return `
    <style>
        html, body {
            overflow: hidden;
            margin: 0 !important;
            padding: 0 !important;
            height: 100%;
            width: 100%;
            background: #1e1e1e;
        }
        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: #f48771;
            background-color: #5a1d1d;
            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="/static/integration.js"></script>
    <script>
        register_message_listener();
    </script>
</body>
</html>`;
  }
}
