import { existsSync } from "node:fs";
import { mkdir, rm, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { ProjectWorkspaceExecutorService } from "../../apps/desktop/src/main/services/project-workspace-executor.js";

function assert(condition: unknown, message: string): asserts condition {
  if (!condition) {
    throw new Error(message);
  }
}

async function writeUtf8(filePath: string, content: string): Promise<void> {
  await mkdir(path.dirname(filePath), { recursive: true });
  await writeFile(filePath, content, "utf8");
}

async function main(): Promise<void> {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const repoRoot = process.cwd();
  const resultPath = path.resolve(process.argv[2] ?? path.join(repoRoot, ".tmp", "ffmpeg-runtime-smoke", "result.json"));
  const tempRoot = path.dirname(resultPath);
  const runtimeManagerModule = await import(pathToFileURL(path.join(repoRoot, "packages", "runtime-manager", "dist", "index.js")).href);
  const powerShellPath = path.join(
    process.env.SYSTEMROOT ?? process.env.WINDIR ?? "C:\\Windows",
    "System32",
    "WindowsPowerShell",
    "v1.0",
    "powershell.exe"
  );
  const RuntimeManager = runtimeManagerModule.RuntimeManager as {
    new (options: { vendorRuntimeDir: string; runtimeDataDir: string; logFilePath: string }): {
      resolveBundledPaths(): {
        ffmpegExecutable?: string;
        ffprobeExecutable?: string;
      };
    };
  };

  await rm(tempRoot, { recursive: true, force: true });
  await mkdir(tempRoot, { recursive: true });
  assert(existsSync(powerShellPath), "Windows PowerShell was not found for workspace automation smoke.");

  const stableRuntimeDir = path.join(tempRoot, "stable-runtime");
  const stableNodePath = path.join(stableRuntimeDir, "node", "node.exe");
  const stableFfmpegPath = path.join(stableRuntimeDir, "ffmpeg", "bin", "ffmpeg.exe");
  const stableFfprobePath = path.join(stableRuntimeDir, "ffmpeg", "bin", "ffprobe.exe");
  await writeUtf8(stableNodePath, "stable-node");
  await writeUtf8(stableFfmpegPath, "stable-ffmpeg");
  await writeUtf8(stableFfprobePath, "stable-ffprobe");

  const stableRuntimeManager = new RuntimeManager({
    vendorRuntimeDir: stableRuntimeDir,
    runtimeDataDir: path.join(tempRoot, "stable-runtime-data"),
    logFilePath: path.join(tempRoot, "stable-runtime-data", "logs", "runtime-manager.log")
  });
  const stablePaths = stableRuntimeManager.resolveBundledPaths();
  assert(stablePaths.ffmpegExecutable === stableFfmpegPath, "Stable bundled runtime did not resolve ffmpeg/bin/ffmpeg.exe.");
  assert(stablePaths.ffprobeExecutable === stableFfprobePath, "Stable bundled runtime did not resolve ffmpeg/bin/ffprobe.exe.");

  const legacyRuntimeDir = path.join(tempRoot, "legacy-runtime");
  const legacyFfmpegPath = path.join(
    legacyRuntimeDir,
    "python",
    "Lib",
    "site-packages",
    "imageio_ffmpeg",
    "binaries",
    "ffmpeg-win-x86_64-v7.1.exe"
  );
  await writeUtf8(legacyFfmpegPath, "legacy-ffmpeg");

  const legacyRuntimeManager = new RuntimeManager({
    vendorRuntimeDir: legacyRuntimeDir,
    runtimeDataDir: path.join(tempRoot, "legacy-runtime-data"),
    logFilePath: path.join(tempRoot, "legacy-runtime-data", "logs", "runtime-manager.log")
  });
  const legacyPaths = legacyRuntimeManager.resolveBundledPaths();
  assert(legacyPaths.ffmpegExecutable === legacyFfmpegPath, "Legacy imageio ffmpeg fallback was not resolved.");
  assert(!legacyPaths.ffprobeExecutable, "Legacy runtime should not invent an ffprobe path when none exists.");

  const projectRoot = path.join(tempRoot, "workspace-project");
  await writeUtf8(path.join(projectRoot, "project.json"), JSON.stringify({
    workspaceAutomation: {
      runtime: "python",
      script: "scripts/echo_env.ps1"
    }
  }, null, 2));
  await writeUtf8(path.join(projectRoot, "scripts", "echo_env.ps1"), [
    "$payload = @{",
    "  FFMPEG_BIN = [string]$env:FFMPEG_BIN",
    "  FFPROBE_BIN = [string]$env:FFPROBE_BIN",
    "  PATH = [string]$env:PATH",
    "} | ConvertTo-Json -Compress",
    "Write-Output 'QJC_WORKSPACE_EVENT\t{\"type\":\"started\",\"runId\":\"ffmpeg-runtime-smoke-run\"}'",
    "Write-Output ('QJC_WORKSPACE_EVENT\t{\"type\":\"completed\",\"content\":' + (ConvertTo-Json $payload -Compress) + '}')",
  ].join("\r\n"));

  const runtimeManagerStub = {
    async status() {
      return {
        payloadState: "ready"
      };
    },
    async syncManagedConfig() {
      return {
        payloadState: "ready"
      };
    },
    resolveBundledPaths() {
      return {
        runtimeDir: stableRuntimeDir,
        nodeExecutable: stableNodePath,
        openClawEntry: path.join(stableRuntimeDir, "openclaw", "index.js"),
        packagedOpenClawEntry: path.join(stableRuntimeDir, "openclaw", "package", "openclaw.mjs"),
        runtimeManifestPath: path.join(stableRuntimeDir, "runtime-manifest.json"),
        defaultConfigPath: path.join(stableRuntimeDir, "config", "openclaw.json"),
        pythonExecutable: powerShellPath,
        pythonManifestPath: path.join(stableRuntimeDir, "python", "python-manifest.json"),
        ffmpegExecutable: stableFfmpegPath,
        ffprobeExecutable: stableFfprobePath,
        playwrightBrowsersPath: path.join(stableRuntimeDir, "playwright-browsers"),
        managedConfigPath: path.join(tempRoot, "stable-runtime-data", "state", "openclaw.runtime.json"),
        readmePath: path.join(stableRuntimeDir, "README.md"),
        runtimeDataDir: path.join(tempRoot, "stable-runtime-data"),
        runtimeStateDir: path.join(tempRoot, "stable-runtime-data", "state"),
        runtimeLogsDir: path.join(tempRoot, "stable-runtime-data", "logs"),
        logFilePath: path.join(tempRoot, "stable-runtime-data", "logs", "runtime-manager.log")
      };
    }
  };

  const executor = new ProjectWorkspaceExecutorService(
    runtimeManagerStub as unknown as ConstructorParameters<typeof ProjectWorkspaceExecutorService>[0]
  );
  const execution = await executor.execute({
    sessionId: "ffmpeg-runtime-smoke-session",
    projectRoot,
    prompt: "verify ffmpeg injection"
  });
  assert("reply" in execution, "Workspace automation did not complete with a reply.");
  const injectedPayload = JSON.parse(execution.reply.content || "{}") as {
    FFMPEG_BIN?: string;
    FFPROBE_BIN?: string;
    PATH?: string;
  };

  assert(injectedPayload.FFMPEG_BIN === stableFfmpegPath, "Workspace automation did not receive the bundled FFMPEG_BIN path.");
  assert(injectedPayload.FFPROBE_BIN === stableFfprobePath, "Workspace automation did not receive the bundled FFPROBE_BIN path.");
  assert(
    (injectedPayload.PATH ?? "").split(path.delimiter).includes(path.dirname(stableNodePath)),
    "Workspace automation PATH did not include the bundled runtime/node directory."
  );

  const summary = {
    ok: true,
    stable: {
      ffmpegExecutable: stablePaths.ffmpegExecutable,
      ffprobeExecutable: stablePaths.ffprobeExecutable
    },
    legacy: {
      ffmpegExecutable: legacyPaths.ffmpegExecutable,
      ffprobeExecutable: legacyPaths.ffprobeExecutable ?? null
    },
    injectedPayload
  };

  await writeUtf8(resultPath, JSON.stringify(summary, null, 2));
  console.log(JSON.stringify(summary, null, 2));
}

main().catch(async (error) => {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const repoRoot = process.cwd();
  const resultPath = path.resolve(process.argv[2] ?? path.join(repoRoot, ".tmp", "ffmpeg-runtime-smoke", "result.json"));
  const failure = {
    ok: false,
    error: error instanceof Error ? error.stack ?? error.message : String(error)
  };

  await writeUtf8(resultPath, JSON.stringify(failure, null, 2));
  console.error(failure.error);
  process.exitCode = 1;
});
