import * as vscode from "vscode";
import * as path from "path";
import { spawn } from "child_process";
import { promisify } from "util";

// 使用 spawn 来执行命令，正确处理路径空格
function execCommand(
  command: string,
  args: string[],
  options: { cwd: string; env?: any }
): Promise<{ stdout: string; stderr: string }> {
  return new Promise((resolve, reject) => {
    // 在 Windows 上，如果路径包含空格，不使用 shell，直接用 spawn
    // spawn 在不使用 shell 时会正确处理带空格的路径
    const child = spawn(command, args, {
      cwd: options.cwd,
      env: options.env || process.env,
      windowsHide: true,
      shell: false, // 不使用 shell，让 spawn 直接执行
    });

    let stdout = "";
    let stderr = "";

    // 在 Windows 上使用 GBK 编码解码输出
    const encoding = process.platform === 'win32' ? 'gbk' : 'utf8';

    child.stdout.on("data", (data) => {
      try {
        // 尝试使用 iconv-lite 解码（如果可用）
        const iconv = require('iconv-lite');
        stdout += iconv.decode(data, encoding);
      } catch {
        // 如果 iconv-lite 不可用，使用默认解码
        stdout += data.toString('utf8');
      }
    });

    child.stderr.on("data", (data) => {
      try {
        const iconv = require('iconv-lite');
        stderr += iconv.decode(data, encoding);
      } catch {
        stderr += data.toString('utf8');
      }
    });

    child.on("close", (code) => {
      if (code === 0) {
        resolve({ stdout, stderr });
      } else {
        const error: any = new Error(`Command failed with exit code ${code}`);
        error.stdout = stdout;
        error.stderr = stderr;
        error.code = code;
        reject(error);
      }
    });

    child.on("error", (error) => {
      reject(error);
    });
  });
}

/**
 * Verilog 项目文件检查结果
 */
export interface VerilogProjectCheck {
  isComplete: boolean;
  hasTopModule: boolean;
  hasTestbench: boolean;
  topModuleFile?: string;
  testbenchFile?: string;
  allVerilogFiles: string[];
  missingFiles: string[];
  errors: string[];
}

/**
 * VCD 生成结果
 */
export interface VCDGenerationResult {
  success: boolean;
  vcdFilePath?: string;
  outputPath?: string;
  message: string;
  stdout?: string;
  stderr?: string;
}

/**
 * 检查项目中的 Verilog 文件完整性
 */
export async function checkVerilogProject(
  projectPath: string
): Promise<VerilogProjectCheck> {
  const result: VerilogProjectCheck = {
    isComplete: false,
    hasTopModule: false,
    hasTestbench: false,
    allVerilogFiles: [],
    missingFiles: [],
    errors: [],
  };

  try {
    // 检查项目路径是否存在
    const projectUri = vscode.Uri.file(projectPath);
    try {
      await vscode.workspace.fs.stat(projectUri);
    } catch (error) {
      result.errors.push(`项目路径不存在: ${projectPath}`);
      return result;
    }

    // 查找所有 Verilog 文件 (.v, .sv)
    const verilogFiles = await findVerilogFiles(projectPath);
    result.allVerilogFiles = verilogFiles;

    if (verilogFiles.length === 0) {
      result.errors.push("项目中没有找到 Verilog 文件 (.v 或 .sv)");
      return result;
    }

    // 分析文件内容，查找 top module 和 testbench
    for (const file of verilogFiles) {
      const fileUri = vscode.Uri.file(file);
      const contentBytes = await vscode.workspace.fs.readFile(fileUri);
      const content = Buffer.from(contentBytes).toString("utf-8");
      const fileName = path.basename(file).toLowerCase();

      // 检查是否是 testbench 文件
      if (
        fileName.includes("tb") ||
        fileName.includes("test") ||
        content.includes("$dumpfile") ||
        content.includes("$dumpvars")
      ) {
        result.hasTestbench = true;
        result.testbenchFile = file;
      }

      // 检查是否包含 module 定义（可能是 top module）
      if (content.match(/module\s+\w+/)) {
        if (!result.hasTopModule && !fileName.includes("tb")) {
          result.hasTopModule = true;
          result.topModuleFile = file;
        }
      }
    }

    // 检查完整性
    if (!result.hasTopModule) {
      result.missingFiles.push("缺少顶层模块文件");
    }

    if (!result.hasTestbench) {
      result.missingFiles.push("缺少 testbench 文件");
    }

    result.isComplete = result.hasTopModule && result.hasTestbench;

    return result;
  } catch (error) {
    result.errors.push(
      `检查项目时出错: ${error instanceof Error ? error.message : "未知错误"}`
    );
    return result;
  }
}

/**
 * 递归查找目录下所有 Verilog 文件
 */
async function findVerilogFiles(dir: string): Promise<string[]> {
  const verilogFiles: string[] = [];

  async function searchDir(currentDir: string) {
    const dirUri = vscode.Uri.file(currentDir);
    const entries = await vscode.workspace.fs.readDirectory(dirUri);

    for (const [fileName, fileType] of entries) {
      const filePath = path.join(currentDir, fileName);

      if (fileType === vscode.FileType.Directory) {
        // 跳过 node_modules 等目录
        if (!fileName.startsWith(".") && fileName !== "node_modules") {
          await searchDir(filePath);
        }
      } else if (fileType === vscode.FileType.File) {
        const ext = path.extname(fileName).toLowerCase();
        if (ext === ".v" || ext === ".sv") {
          verilogFiles.push(filePath);
        }
      }
    }
  }

  await searchDir(dir);
  return verilogFiles;
}

/**
 * 获取 iverilog 可执行文件路径
 */
async function getIverilogPath(extensionPath: string): Promise<string> {
  const platform = process.platform;
  let iverilogBin = "";

  if (platform === "win32") {
    iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog.exe");
  } else if (platform === "darwin") {
    iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog");
  } else {
    // Linux
    iverilogBin = path.join(extensionPath, "tools", "iverilog", "bin", "iverilog");
  }

  // 如果插件包中没有，尝试使用系统安装的 iverilog
  const iverilogUri = vscode.Uri.file(iverilogBin);
  try {
    await vscode.workspace.fs.stat(iverilogUri);
    return iverilogBin;
  } catch {
    return "iverilog"; // 使用系统 PATH 中的 iverilog
  }
}

/**
 * 获取 vvp 可执行文件路径
 */
async function getVvpPath(extensionPath: string): Promise<string> {
  const platform = process.platform;
  let vvpBin = "";

  if (platform === "win32") {
    vvpBin = path.join(extensionPath, "tools", "iverilog", "bin", "vvp.exe");
  } else if (platform === "darwin") {
    vvpBin = path.join(extensionPath, "tools", "iverilog", "bin", "vvp");
  } else {
    // Linux
    vvpBin = path.join(extensionPath, "tools", "iverilog", "bin", "vvp");
  }

  // 如果插件包中没有，尝试使用系统安装的 vvp
  const vvpUri = vscode.Uri.file(vvpBin);
  try {
    await vscode.workspace.fs.stat(vvpUri);
    return vvpBin;
  } catch {
    return "vvp"; // 使用系统 PATH 中的 vvp
  }
}

/**
 * 运行 iverilog 生成 VCD 文件
 */
export async function generateVCD(
  projectPath: string,
  extensionPath: string
): Promise<VCDGenerationResult> {
  try {
    // 1. 检查项目完整性
    const projectCheck = await checkVerilogProject(projectPath);

    if (!projectCheck.isComplete) {
      return {
        success: false,
        message: `项目文件不完整:\n${projectCheck.missingFiles.join("\n")}\n${projectCheck.errors.join("\n")}`,
      };
    }

    // 2. 获取 iverilog 和 vvp 路径
    const iverilogPath = await getIverilogPath(extensionPath);
    const vvpPath = await getVvpPath(extensionPath);

    // 3. 准备输出路径
    const outputDir = projectPath;
    const outputFile = path.join(outputDir, "simulation.vvp");

    // 4. 设置环境变量，确保 iverilog 能找到库文件
    const libPath = path.join(extensionPath, "tools", "iverilog", "lib");
    const env = {
      ...process.env,
      IVERILOG_ROOT: path.join(extensionPath, "tools", "iverilog"),
    };

    // 5. 构建 iverilog 编译参数
    const compileArgs = ["-o", outputFile, ...projectCheck.allVerilogFiles];

    console.log("执行编译命令:", iverilogPath, compileArgs.join(" "));
    console.log("IVERILOG_ROOT:", env.IVERILOG_ROOT);

    // 6. 执行编译
    let compileResult;
    try {
      compileResult = await execCommand(iverilogPath, compileArgs, {
        cwd: projectPath,
        env: env,
      });
    } catch (error: any) {
      return {
        success: false,
        message: `iverilog 编译失败:\n${error.message}`,
        stderr: error.stderr,
        stdout: error.stdout,
      };
    }

    // 7. 执行仿真生成 VCD
    const simArgs = [outputFile];
    console.log("执行仿真命令:", vvpPath, simArgs.join(" "));

    let simResult;
    try {
      simResult = await execCommand(vvpPath, simArgs, {
        cwd: projectPath,
        env: env,
      });
    } catch (error: any) {
      return {
        success: false,
        message: `VVP 仿真失败:\n${error.message}`,
        stderr: error.stderr,
        stdout: error.stdout,
      };
    }

    // 8. 查找生成的 VCD 文件
    const projectUri = vscode.Uri.file(projectPath);
    const entries = await vscode.workspace.fs.readDirectory(projectUri);
    const vcdFiles = entries
      .filter(([fileName, fileType]) => fileType === vscode.FileType.File && fileName.endsWith('.vcd'))
      .map(([fileName]) => fileName);

    if (vcdFiles.length === 0) {
      return {
        success: false,
        message: "VCD 文件未生成。请确保 testbench 中包含 $dumpfile 和 $dumpvars 语句。",
        stdout: simResult.stdout,
      };
    }

    // 使用找到的第一个 VCD 文件
    const vcdFile = path.join(projectPath, vcdFiles[0]);

    // 9. 清理中间文件
    try {
      const outputUri = vscode.Uri.file(outputFile);
      await vscode.workspace.fs.stat(outputUri);
      await vscode.workspace.fs.delete(outputUri);
    } catch (error) {
      // 忽略清理错误
    }

    return {
      success: true,
      vcdFilePath: vcdFile,
      outputPath: projectPath,
      message: `VCD 文件生成成功！\n路径: ${vcdFile}`,
      stdout: simResult.stdout,
    };
  } catch (error) {
    return {
      success: false,
      message: `生成 VCD 文件时出错: ${error instanceof Error ? error.message : "未知错误"}`,
    };
  }
}

/**
 * 检查 iverilog 是否可用
 */
export async function checkIverilogAvailable(
  extensionPath: string
): Promise<{ available: boolean; version?: string; message: string }> {
  try {
    const iverilogPath = await getIverilogPath(extensionPath);

    // 检查文件是否存在
    const iverilogUri = vscode.Uri.file(iverilogPath);
    try {
      await vscode.workspace.fs.stat(iverilogUri);
    } catch (error) {
      return {
        available: false,
        message: `iverilog 不可用。未找到文件: ${iverilogPath}`,
      };
    }

    // 设置环境变量
    const env = {
      ...process.env,
      IVERILOG_ROOT: path.join(extensionPath, "tools", "iverilog"),
    };

    const result = await execCommand(iverilogPath, ["-V"], {
      cwd: path.dirname(iverilogPath),
      env: env,
    });
    const version = result.stdout.trim().split("\n")[0];

    return {
      available: true,
      version: version,
      message: `iverilog 可用: ${version}`,
    };
  } catch (error: any) {
    return {
      available: false,
      message: `iverilog 执行失败: ${error.message}\n${error.stderr || ""}`,
    };
  }
}

/**
 * 要 dump 的模块定义
 */
export interface DumpModule {
  name: string;   // 模块名（用于 VCD 文件名和宏名）
  path: string;   // 实例路径（如 dut.u_tx）
}

/**
 * 多 VCD 生成结果
 */
export interface MultiVCDResult {
  success: boolean;
  vcdFiles: Array<{
    moduleName: string;
    vcdPath: string;
    success: boolean;
    error?: string;
  }>;
  message: string;
  stdout?: string;
}

/**
 * 在 testbench 中注入条件编译代码
 * 将原有的 $dumpfile/$dumpvars 替换为条件编译版本
 */
function injectConditionalDump(
  tbContent: string,
  dumpModules: DumpModule[],
  vcdDir: string
): string {
  // 匹配 $dumpfile 和 $dumpvars 语句（可能跨多行）
  const dumpPattern = /(\$dumpfile\s*\([^)]+\)\s*;[\s\S]*?\$dumpvars\s*\([^)]+\)\s*;)/g;

  // 生成条件编译代码
  const conditionalCode = generateConditionalDumpCode(dumpModules, vcdDir);

  // 替换原有的 dump 语句
  const modified = tbContent.replace(dumpPattern, conditionalCode);

  // 如果没有找到匹配，尝试单独匹配 $dumpfile
  if (modified === tbContent) {
    const singleDumpPattern = /\$dumpfile\s*\([^)]+\)\s*;/g;
    return tbContent.replace(singleDumpPattern, conditionalCode);
  }

  return modified;
}

/**
 * 生成条件编译的 dump 代码
 */
function generateConditionalDumpCode(
  dumpModules: DumpModule[],
  vcdDir: string
): string {
  if (dumpModules.length === 0) {
    return '$dumpfile("output.vcd");\n    $dumpvars(0, dut);';
  }

  const lines: string[] = [];

  dumpModules.forEach((module, index) => {
    const macroName = `DUMP_${module.name.toUpperCase()}`;
    const vcdPath = `${vcdDir}/${module.name}.vcd`;
    const directive = index === 0 ? '`ifdef' : '`elsif';

    lines.push(`${directive} ${macroName}`);
    lines.push(`    $dumpfile("${vcdPath}");`);
    lines.push(`    $dumpvars(1, ${module.path});`);
  });

  // 添加默认分支（使用第一个模块）
  lines.push('`else');
  lines.push(`    $dumpfile("${vcdDir}/${dumpModules[0].name}.vcd");`);
  lines.push(`    $dumpvars(1, ${dumpModules[0].path});`);
  lines.push('`endif');

  return lines.join('\n');
}

/**
 * 生成多个 VCD 文件（为不同子模块）
 */
export async function generateMultiVCD(
  projectPath: string,
  extensionPath: string,
  tbPath: string,
  dumpModules: DumpModule[],
  vcdDir: string = 'vcd'
): Promise<MultiVCDResult> {
  const results: MultiVCDResult['vcdFiles'] = [];
  let allStdout = '';

  try {
    // 1. 创建 vcd 目录
    const vcdDirPath = path.join(projectPath, vcdDir);
    const vcdDirUri = vscode.Uri.file(vcdDirPath);
    try {
      await vscode.workspace.fs.createDirectory(vcdDirUri);
    } catch {
      // 目录可能已存在
    }

    // 2. 读取原始 testbench
    const tbFullPath = path.isAbsolute(tbPath) ? tbPath : path.join(projectPath, tbPath);
    const tbUri = vscode.Uri.file(tbFullPath);
    const tbBytes = await vscode.workspace.fs.readFile(tbUri);
    const originalTb = Buffer.from(tbBytes).toString('utf-8');

    // 3. 注入条件编译代码
    const modifiedTb = injectConditionalDump(originalTb, dumpModules, vcdDir);
    await vscode.workspace.fs.writeFile(tbUri, Buffer.from(modifiedTb, 'utf-8'));

    console.log('[generateMultiVCD] Testbench 已修改，开始多次仿真...');

    // 4. 获取工具路径
    const iverilogPath = await getIverilogPath(extensionPath);
    const vvpPath = await getVvpPath(extensionPath);
    const env = {
      ...process.env,
      IVERILOG_ROOT: path.join(extensionPath, "tools", "iverilog"),
    };

    // 5. 获取所有 Verilog 文件
    const projectCheck = await checkVerilogProject(projectPath);
    const outputFile = path.join(projectPath, "simulation.vvp");

    // 6. 循环执行仿真
    for (const module of dumpModules) {
      const macroName = `DUMP_${module.name.toUpperCase()}`;
      const vcdPath = path.join(vcdDirPath, `${module.name}.vcd`);

      console.log(`[generateMultiVCD] 仿真模块: ${module.name} (${macroName})`);

      try {
        // 编译（带宏定义）
        const compileArgs = [
          `-D${macroName}`,
          "-o", outputFile,
          ...projectCheck.allVerilogFiles
        ];
        await execCommand(iverilogPath, compileArgs, { cwd: projectPath, env });

        // 仿真
        const simResult = await execCommand(vvpPath, [outputFile], { cwd: projectPath, env });
        allStdout += `\n[${module.name}] ${simResult.stdout}`;

        results.push({
          moduleName: module.name,
          vcdPath: vcdPath,
          success: true
        });
      } catch (error: any) {
        console.error(`[generateMultiVCD] 模块 ${module.name} 仿真失败:`, error.message);
        results.push({
          moduleName: module.name,
          vcdPath: vcdPath,
          success: false,
          error: error.message
        });
        // 继续执行其他模块
      }
    }

    // 7. 清理中间文件
    try {
      await vscode.workspace.fs.delete(vscode.Uri.file(outputFile));
    } catch {
      // 忽略
    }

    const successCount = results.filter(r => r.success).length;
    return {
      success: successCount > 0,
      vcdFiles: results,
      message: `生成完成：${successCount}/${dumpModules.length} 个 VCD 文件成功`,
      stdout: allStdout
    };

  } catch (error) {
    return {
      success: false,
      vcdFiles: results,
      message: `生成多 VCD 文件失败: ${error instanceof Error ? error.message : '未知错误'}`
    };
  }
}
