/**
 * 工具执行器
 * 接收后端的 tool_call 事件，执行本地工具，返回结果
 */
import * as vscode from "vscode";
import * as path from "path";
import * as os from "os";
import * as fs from "fs";
import { readFileContent, readDirectory } from "../utils/readFiles";
import { createOrOverwriteFile } from "../utils/createFiles";
import { resolveWorkspaceFilePath, showFileDiff } from "../utils/fileDiff";
import { changeTracker } from "./changeTracker";
import {
  generateVCD,
  checkIverilogAvailable,
  generateMultiVCD,
  DumpModule,
} from "../utils/iverilogRunner";
import { analyzeVcdFile } from "../utils/vcdParser";
import {
  executeWaveformTrace,
  WaveformTraceArgs,
} from "../utils/waveformTracer";
import {
  submitToolResult,
  createSuccessResult,
  createBusinessErrorResult,
  createSystemErrorResult,
} from "./apiClient";
import type {
  ToolCallRequest,
  ToolName,
  FileReadArgs,
  FileWriteArgs,
  FileDeleteArgs,
  FileListArgs,
  SyntaxCheckArgs,
  IverilogArgs,
  SimulationArgs,
  WaveformSummaryArgs,
  KnowledgeSaveArgs,
  KnowledgeLoadArgs,
} from "../types/api";

/**
 * 工具执行器上下文
 */
export interface ToolExecutorContext {
  /** 扩展路径（用于 iverilog） */
  extensionPath: string;
  /** 工作区路径 */
  workspacePath: string;
}

/**
 * 执行工具调用
 * @param request 工具调用请求
 * @param context 执行上下文
 */
export async function executeToolCall(
  request: ToolCallRequest,
  context: ToolExecutorContext,
): Promise<void> {
  const toolName = request.params.name as ToolName;
  const args = request.params.arguments;
  const callId = request.id;

  console.log(`[ToolExecutor] 执行工具: ${toolName}, callId=${callId}`, args);

  try {
    let resultText: string;

    switch (toolName) {
      case "file_read":
        resultText = await executeFileRead(args as unknown as FileReadArgs);
        break;
      case "file_write":
        resultText = await executeFileWrite(args as unknown as FileWriteArgs);
        break;
      case "file_delete":
        resultText = await executeFileDelete(args as unknown as FileDeleteArgs);
        break;
      case "file_list":
        resultText = await executeFileList(args as unknown as FileListArgs);
        break;
      case "syntax_check":
        resultText = await executeSyntaxCheck(
          args as unknown as SyntaxCheckArgs,
          context,
        );
        break;
      case "iverilog":
        resultText = await executeIverilog(
          args as unknown as IverilogArgs,
          context,
        );
        break;
      case "simulation":
        resultText = await executeSimulation(
          args as unknown as SimulationArgs,
          context,
        );
        break;
      case "waveform_summary":
        resultText = await executeWaveformSummary(
          args as unknown as WaveformSummaryArgs,
        );
        break;
      case "waveform_trace":
        resultText = await executeWaveformTrace(
          args as unknown as WaveformTraceArgs,
          context,
        );
        break;
      case "knowledge_save":
        resultText = await executeKnowledgeSave(
          args as unknown as KnowledgeSaveArgs,
        );
        break;
      case "knowledge_load":
        resultText = await executeKnowledgeLoad();
        break;
      default:
        throw new Error(`未知工具: ${toolName}`);
    }

    // 提交成功结果
    const result = createSuccessResult(callId, resultText);
    await submitToolResult(result);
    console.log(`[ToolExecutor] 工具执行成功: ${toolName}, callId=${callId}`);
  } catch (error) {
    const errorMessage = error instanceof Error ? error.message : "未知错误";
    console.error(
      `[ToolExecutor] 工具执行失败: ${toolName}, callId=${callId}`,
      error,
    );

    // 提交错误结果
    const result = createBusinessErrorResult(callId, errorMessage);
    await submitToolResult(result);
  }
}

/**
 * 执行 file_read 工具
 */
async function executeFileRead(args: FileReadArgs): Promise<string> {
  const content = await readFileContent(args.path);
  return content;
}

/**
 * 执行 file_write 工具
 */
async function executeFileWrite(args: FileWriteArgs): Promise<string> {
  const absolutePath = resolveWorkspaceFilePath(args.path);
  const existedBeforeWrite = fs.existsSync(absolutePath);
  const oldContent = existedBeforeWrite ? await readFileContent(args.path) : "";

  await createOrOverwriteFile(args.path, args.content);

  // 记录文件变更
  try {
    changeTracker.trackChange(args.path, oldContent, args.content);
  } catch (error) {
    console.warn("[ToolExecutor] 记录文件变更失败:", error);
  }

  // Verilog 文件添加知识图谱提示
  const isVerilogFile = args.path.endsWith(".v") || args.path.endsWith(".sv");
  if (isVerilogFile) {
    return `文件已写入: ${args.path}\n\n[提示] 如有新信号或规则，请更新知识图谱`;
  }

  return `文件已写入: ${args.path}`;
}

/**
 * 执行 file_delete 工具
 * 删除指定路径的文件（带用户确认）
 */
async function executeFileDelete(args: FileDeleteArgs): Promise<string> {
  const filePath = args.path;

  // 获取工作区路径
  const workspaceFolders = vscode.workspace.workspaceFolders;
  if (!workspaceFolders || workspaceFolders.length === 0) {
    throw new Error("请先打开一个工作区");
  }

  const workspacePath = workspaceFolders[0].uri.fsPath;

  // 解析文件路径（支持相对路径和绝对路径）
  const absolutePath = path.isAbsolute(filePath)
    ? filePath
    : path.join(workspacePath, filePath);

  // 检查文件是否存在
  if (!fs.existsSync(absolutePath)) {
    throw new Error(`文件不存在: ${filePath}`);
  }

  // 检查是否为文件（不允许删除目录）
  const stat = fs.statSync(absolutePath);
  if (stat.isDirectory()) {
    throw new Error(`不能删除目录，请指定文件路径: ${filePath}`);
  }

  // 验证文件路径在工作区内
  const isInWorkspace = workspaceFolders.some((folder) =>
    absolutePath.startsWith(folder.uri.fsPath),
  );

  if (!isInWorkspace) {
    throw new Error("只能删除工作区内的文件");
  }

  // 保护敏感文件
  const protectedFiles = [
    "package.json",
    "tsconfig.json",
    ".git",
    "node_modules",
  ];

  const fileName = path.basename(absolutePath);
  if (protectedFiles.includes(fileName)) {
    throw new Error(`不允许删除系统文件: ${fileName}`);
  }

  // 弹出确认对话框
  const confirmed = await vscode.window.showWarningMessage(
    `确定要删除文件吗？\n\n📄 ${path.basename(filePath)}\n📁 ${path.dirname(filePath)}`,
    {
      modal: true, // 模态对话框，阻止其他操作
      detail: "⚠️ 文件将被移到回收站，可以恢复",
    },
    "确定删除",
    "取消",
  );

  // 用户取消或关闭对话框
  if (confirmed !== "确定删除") {
    throw new Error("用户取消了删除操作");
  }

  // 读取文件内容用于变更追踪
  const oldContent = fs.readFileSync(absolutePath, "utf-8");

  // 记录删除变更
  const relativePath = path.relative(workspacePath, absolutePath);
  changeTracker.trackChange(relativePath, oldContent, "");

  // 删除文件（移到回收站）
  const uri = vscode.Uri.file(absolutePath);
  await vscode.workspace.fs.delete(uri, {
    recursive: false, // 不是目录，设为 false
    useTrash: true, // 移到回收站而非永久删除
  });

  // Verilog 文件添加知识图谱提示
  const isVerilogFile = filePath.endsWith(".v") || filePath.endsWith(".sv");
  if (isVerilogFile) {
    return `文件已删除: ${filePath}\n\n[提示] 请删除知识图谱中相关节点`;
  }

  return `文件已删除: ${filePath}`;
}

/**
 * 执行 file_list 工具
 */
async function executeFileList(args: FileListArgs): Promise<string> {
  const dirPath = args.path || ".";
  const extensions = args.extension ? [args.extension] : undefined;

  const files = await readDirectory(dirPath, extensions);
  const fileList = files.map((f) => f.path).join("\n");

  return fileList || "（目录为空）";
}

/**
 * 执行 syntax_check 工具
 * 将代码写入临时文件，调用 iverilog 检查语法
 */
async function executeSyntaxCheck(
  args: SyntaxCheckArgs,
  context: ToolExecutorContext,
): Promise<string> {
  // 检查 iverilog 是否可用
  const iverilogCheck = await checkIverilogAvailable(context.extensionPath);
  if (!iverilogCheck.available) {
    throw new Error(`iverilog 不可用: ${iverilogCheck.message}`);
  }

  // 创建临时文件
  const tempDir = os.tmpdir();
  const tempFile = path.join(tempDir, `iccoder_syntax_${Date.now()}.v`);

  try {
    // 写入代码到临时文件
    fs.writeFileSync(tempFile, args.code, "utf-8");

    // 调用 iverilog 进行语法检查
    const { spawn } = require("child_process");
    const iverilogPath = getIverilogPath(context.extensionPath);

    return new Promise((resolve, reject) => {
      const child = spawn(iverilogPath, ["-t", "null", tempFile], {
        cwd: tempDir,
        env: {
          ...process.env,
          IVERILOG_ROOT: path.join(context.extensionPath, "tools", "iverilog"),
        },
      });

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

      child.stdout.on("data", (data: Buffer) => {
        stdout += data.toString();
      });

      child.stderr.on("data", (data: Buffer) => {
        stderr += data.toString();
      });

      child.on("close", (code: number) => {
        // 清理临时文件
        try {
          fs.unlinkSync(tempFile);
        } catch (e) {
          // 忽略清理错误
        }

        if (code === 0) {
          resolve("语法检查通过，无错误。");
        } else {
          resolve(`语法检查发现错误:\n${stderr || stdout}`);
        }
      });

      child.on("error", (error: Error) => {
        try {
          fs.unlinkSync(tempFile);
        } catch (e) {
          // 忽略清理错误
        }
        reject(error);
      });
    });
  } catch (error) {
    // 确保清理临时文件
    try {
      fs.unlinkSync(tempFile);
    } catch (e) {
      // 忽略
    }
    throw error;
  }
}

/**
 * 执行 iverilog 工具
 * 直接执行 iverilog 命令
 */
async function executeIverilog(
  args: IverilogArgs,
  context: ToolExecutorContext,
): Promise<string> {
  // 检查 iverilog 是否可用
  const iverilogCheck = await checkIverilogAvailable(context.extensionPath);
  if (!iverilogCheck.available) {
    throw new Error(`iverilog 不可用: ${iverilogCheck.message}`);
  }

  // 获取工作目录
  const workspaceFolders = vscode.workspace.workspaceFolders;
  if (!workspaceFolders || workspaceFolders.length === 0) {
    throw new Error("没有打开的工作区");
  }
  const projectPath = workspaceFolders[0].uri.fsPath;
  const workDir = args.workDir
    ? path.join(projectPath, args.workDir)
    : projectPath;

  // 解析参数
  const iverilogPath = getIverilogPath(context.extensionPath);
  const cmdArgs = args.args.split(/\s+/).filter((a) => a.length > 0);

  const { spawn } = require("child_process");

  return new Promise((resolve, reject) => {
    const child = spawn(iverilogPath, cmdArgs, {
      cwd: workDir,
      env: {
        ...process.env,
        IVERILOG_ROOT: path.join(context.extensionPath, "tools", "iverilog"),
      },
    });

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

    child.stdout.on("data", (data: Buffer) => {
      stdout += data.toString();
    });

    child.stderr.on("data", (data: Buffer) => {
      stderr += data.toString();
    });

    child.on("close", (code: number) => {
      const output = stderr || stdout || "(无输出)";
      if (code === 0) {
        resolve(`执行成功\n${output}`);
      } else {
        resolve(`执行失败 (exit code: ${code})\n${output}`);
      }
    });

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

/**
 * 执行 simulation 工具
 */
async function executeSimulation(
  args: SimulationArgs,
  context: ToolExecutorContext,
): Promise<string> {
  // 获取工作区路径
  const workspaceFolders = vscode.workspace.workspaceFolders;
  if (!workspaceFolders || workspaceFolders.length === 0) {
    throw new Error("请先打开一个工作区");
  }

  const projectPath = workspaceFolders[0].uri.fsPath;

  // 检查是否有 dumpModules 参数（多 VCD 模式）
  if (args.dumpModules) {
    const modules = parseDumpModules(args.dumpModules);
    const vcdDir = args.vcdDir || "vcd";

    const result = await generateMultiVCD(
      projectPath,
      context.extensionPath,
      args.tbPath,
      modules,
      vcdDir,
    );

    if (result.success) {
      const vcdList = result.vcdFiles
        .map(
          (f) =>
            `- ${f.moduleName}: ${f.success ? f.vcdPath : "失败 - " + f.error}`,
        )
        .join("\n");
      return `${result.message}\n\nVCD 文件列表:\n${vcdList}${result.stdout ? "\n\n仿真输出:" + result.stdout : ""}`;
    } else {
      throw new Error(result.message);
    }
  }

  // 原有单 VCD 逻辑
  const result = await generateVCD(projectPath, context.extensionPath);

  if (result.success) {
    let message = result.message;
    if (result.stdout) {
      message += `\n\n仿真输出:\n${result.stdout}`;
    }
    return message;
  } else {
    let errorMessage = result.message;
    if (result.stderr) {
      errorMessage += `\n\n错误输出:\n${result.stderr}`;
    }
    throw new Error(errorMessage);
  }
}

/**
 * 解析 dumpModules 参数
 * 格式：name:path,name:path
 */
function parseDumpModules(dumpModules: string): DumpModule[] {
  return dumpModules.split(",").map((item) => {
    const [name, modulePath] = item.trim().split(":");
    return { name: name.trim(), path: modulePath.trim() };
  });
}

/**
 * 执行 waveform_summary 工具
 * 解析 VCD 文件并返回波形摘要
 */
async function executeWaveformSummary(
  args: WaveformSummaryArgs,
): Promise<string> {
  const { vcdPath, signals, checkpoints } = args;

  // 获取工作区路径
  const workspaceFolders = vscode.workspace.workspaceFolders;
  if (!workspaceFolders || workspaceFolders.length === 0) {
    throw new Error("请先打开一个工作区");
  }

  const workspacePath = workspaceFolders[0].uri.fsPath;

  // 解析 VCD 文件路径（支持相对路径）
  const absolutePath = path.isAbsolute(vcdPath)
    ? vcdPath
    : path.join(workspacePath, vcdPath);

  // 检查文件是否存在
  if (!fs.existsSync(absolutePath)) {
    throw new Error(`VCD 文件不存在: ${vcdPath}`);
  }

  // 解析检查点时间
  const checkpoint = checkpoints ? parseInt(checkpoints, 10) : undefined;

  // 调用 VCD 解析器
  const result = analyzeVcdFile(absolutePath, signals, checkpoint);

  return result;
}

/**
 * 执行 knowledge_save 工具
 * 保存知识图谱到 .iccoder/knowledge.json
 */
async function executeKnowledgeSave(args: KnowledgeSaveArgs): Promise<string> {
  const workspaceFolder = getWorkspaceFolder();
  if (!workspaceFolder) {
    throw new Error("请先打开一个工作区");
  }

  const iccoderDirUri = vscode.Uri.joinPath(workspaceFolder.uri, ".iccoder");
  const knowledgeUri = vscode.Uri.joinPath(iccoderDirUri, "knowledge.json");

  // 确保 .iccoder 目录存在（兼容远程/虚拟工作区）
  await vscode.workspace.fs.createDirectory(iccoderDirUri);

  // 写入知识图谱（UTF-8）
  await vscode.workspace.fs.writeFile(
    knowledgeUri,
    Buffer.from(args.data || "", "utf-8"),
  );

  return `知识图谱已保存: .iccoder/knowledge.json`;
}

/**
 * 执行 knowledge_load 工具
 * 从 .iccoder/knowledge.json 加载知识图谱
 */
async function executeKnowledgeLoad(): Promise<string> {
  const workspaceFolder = getWorkspaceFolder();
  if (!workspaceFolder) {
    throw new Error("请先打开一个工作区");
  }

  const knowledgeUri = vscode.Uri.joinPath(
    workspaceFolder.uri,
    ".iccoder",
    "knowledge.json",
  );

  try {
    const bytes = await vscode.workspace.fs.readFile(knowledgeUri);
    const content = Buffer.from(bytes).toString("utf-8");
    return content;
  } catch (error) {
    // 文件不存在：返回空图谱
    if (
      error instanceof vscode.FileSystemError &&
      error.code === "FileNotFound"
    ) {
      // 与后端 KnowledgeGraph 结构保持一致（nodes/edges + nodeClass 多态字段）
      return JSON.stringify({
        taskId: "",
        version: 1,
        module: null,
        nodes: [],
        edges: [],
      });
    }
    throw error;
  }
}

function getWorkspaceFolder(): vscode.WorkspaceFolder | undefined {
  const folders = vscode.workspace.workspaceFolders;
  if (!folders || folders.length === 0) {
    return undefined;
  }

  const activeUri = vscode.window.activeTextEditor?.document?.uri;
  const activeFolder = activeUri
    ? vscode.workspace.getWorkspaceFolder(activeUri)
    : undefined;
  return activeFolder ?? folders[0];
}

/**
 * 获取 iverilog 路径
 */
function getIverilogPath(extensionPath: string): string {
  const platform = process.platform;
  if (platform === "win32") {
    return path.join(extensionPath, "tools", "iverilog", "bin", "iverilog.exe");
  } else {
    return path.join(extensionPath, "tools", "iverilog", "bin", "iverilog");
  }
}

/**
 * 创建工具执行器上下文
 */
export function createToolExecutorContext(
  extensionPath: string,
): ToolExecutorContext {
  const workspaceFolders = vscode.workspace.workspaceFolders;
  const workspacePath = workspaceFolders?.[0]?.uri.fsPath || "";

  return {
    extensionPath,
    workspacePath,
  };
}
