#!/usr/bin/env node

import { execFileSync } from "node:child_process"
import { createRequire } from "node:module"
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs"
import { join, resolve } from "node:path"

const repoRoot = resolve(import.meta.dirname, "..", "..")
const runtimeDir = process.env.QJCLAW_SMOKE_RUNTIME_DIR || join(repoRoot, "vendor", "openclaw-runtime")
const tmpRoot = join(repoRoot, ".tmp", "mac-workspace-service-smoke")
const compileDir = join(tmpRoot, "compiled")
const projectRoot = join(tmpRoot, "project")
const runtimeDataDir = join(tmpRoot, "runtime-data")

let failures = 0

function check(label, condition, detail) {
  if (condition) {
    console.log(`  PASS: ${label}`)
  } else {
    console.error(`  FAIL: ${label}${detail ? ` — ${detail}` : ""}`)
    failures++
  }
}

function checkFile(label, filePath) {
  check(label, existsSync(filePath), `not found: ${filePath}`)
}

function emitSummary() {
  console.log("")
  if (failures === 0) {
    console.log("mac-workspace-service-smoke: ALL PASSED")
  } else {
    console.error(`mac-workspace-service-smoke: ${failures} FAILURE(S)`)
    process.exit(1)
  }
}

async function main() {
  console.log("mac-workspace-service-smoke: validating ProjectWorkspaceExecutorService with bundled Python")

  const pythonExe = join(runtimeDir, "python", "bin", "python3")
  const nodeExe = join(runtimeDir, "node", "bin", "node")
  const ffmpegExe = join(runtimeDir, "ffmpeg", "bin", "ffmpeg")
  const ffprobeExe = join(runtimeDir, "ffmpeg", "bin", "ffprobe")
  const playwrightBrowsersPath = join(runtimeDir, "playwright-browsers")

  checkFile("runtime-manifest.json", join(runtimeDir, "runtime-manifest.json"))
  checkFile("bundled python3", pythonExe)
  checkFile("bundled node", nodeExe)

  if (failures > 0) {
    emitSummary()
    return
  }

  rmSync(tmpRoot, { recursive: true, force: true })
  mkdirSync(compileDir, { recursive: true })
  mkdirSync(projectRoot, { recursive: true })
  mkdirSync(join(runtimeDataDir, "state"), { recursive: true })
  mkdirSync(join(runtimeDataDir, "logs"), { recursive: true })

  execFileSync("corepack", [
    "pnpm",
    "--dir",
    join(repoRoot, "apps", "desktop"),
    "exec",
    "tsup",
    "src/main/services/project-workspace-executor.ts",
    "--no-config",
    "--format",
    "cjs",
    "--platform",
    "node",
    "--target",
    "node20",
    "--out-dir",
    compileDir,
    "--external",
    "electron",
  ], {
    cwd: repoRoot,
    stdio: "inherit",
  })

  const compiledService = join(compileDir, "project-workspace-executor.js")
  checkFile("compiled ProjectWorkspaceExecutorService", compiledService)
  if (failures > 0) {
    emitSummary()
    return
  }

  const projectJson = {
    workspaceAutomation: {
      runtime: "python",
      script: "run.py",
      args: ["--prompt", "{prompt}", "--session", "{sessionId}"],
      env: {
        QJC_SMOKE_PROJECT_ROOT: "{projectRoot}",
        QJC_SMOKE_ATTACHMENT_PATHS: "{attachmentPathsJson}",
      },
    },
  }
  writeFileSync(join(projectRoot, "project.json"), JSON.stringify(projectJson, null, 2), "utf8")

  const runPy = `
import argparse
import json
import os
import sys

parser = argparse.ArgumentParser()
parser.add_argument("--prompt", required=True)
parser.add_argument("--session", required=True)
args = parser.parse_args()

checks = {
    "prompt": args.prompt,
    "session": args.session,
    "project_root": os.environ.get("QJC_SMOKE_PROJECT_ROOT", ""),
    "runtime_dir": os.environ.get("QJCLAW_BUNDLED_RUNTIME_DIR", ""),
    "playwright": os.environ.get("PLAYWRIGHT_BROWSERS_PATH", ""),
    "ffmpeg": os.environ.get("FFMPEG_BIN", ""),
    "ffprobe": os.environ.get("FFPROBE_BIN", ""),
    "python": sys.executable,
}

missing = [
    name for name in ["project_root", "runtime_dir", "playwright", "python"]
    if not checks[name]
]
if missing:
    print("QJC_WORKSPACE_EVENT\\t" + json.dumps({
        "type": "error",
        "message": "missing env: " + ",".join(missing),
    }))
    sys.exit(0)

print("QJC_WORKSPACE_EVENT\\t" + json.dumps({
    "type": "started",
    "runId": "mac-workspace-service-smoke-run",
}))
print("QJC_WORKSPACE_EVENT\\t" + json.dumps({
    "type": "status",
    "stage": "python-automation",
    "label": "Bundled Python automation started",
}))
print("QJC_WORKSPACE_EVENT\\t" + json.dumps({
    "type": "completed",
    "content": "service smoke ok: " + json.dumps(checks, sort_keys=True),
}))
`.trimStart()
  writeFileSync(join(projectRoot, "run.py"), runPy, "utf8")

  const require = createRequire(import.meta.url)
  const { ProjectWorkspaceExecutorService } = require(compiledService)
  const statuses = []
  const started = []
  let syncedAction = null

  const runtimeManager = {
    status: async () => ({ payloadState: "ready" }),
    syncManagedConfig: async (action) => {
      syncedAction = action
    },
    resolveBundledPaths: () => ({
      runtimeDir,
      nodeExecutable: nodeExe,
      openClawEntry: join(runtimeDir, "openclaw", "index.js"),
      packagedOpenClawEntry: join(runtimeDir, "openclaw", "package", "openclaw.mjs"),
      runtimeManifestPath: join(runtimeDir, "runtime-manifest.json"),
      defaultConfigPath: join(runtimeDir, "config", "openclaw.json"),
      pythonExecutable: pythonExe,
      pythonManifestPath: join(runtimeDir, "python", "python-manifest.json"),
      ffmpegExecutable: existsSync(ffmpegExe) ? ffmpegExe : undefined,
      ffprobeExecutable: existsSync(ffprobeExe) ? ffprobeExe : undefined,
      playwrightBrowsersPath,
      managedConfigPath: join(runtimeDataDir, "state", "openclaw.runtime.json"),
      readmePath: join(runtimeDir, "README.md"),
      runtimeDataDir,
      runtimeStateDir: join(runtimeDataDir, "state"),
      runtimeLogsDir: join(runtimeDataDir, "logs"),
      logFilePath: join(runtimeDataDir, "logs", "runtime.log"),
    }),
  }

  try {
    const service = new ProjectWorkspaceExecutorService(runtimeManager)
    const result = await service.execute({
      sessionId: "mac-workspace-service-smoke-session",
      projectRoot,
      prompt: "prepared smoke prompt",
      userPrompt: "human smoke prompt",
      runId: "outer-smoke-run",
      attachments: [],
    }, {
      onStarted: (runId) => started.push(runId),
      onStatus: (stage, label) => statuses.push({ stage, label }),
    })

    check("syncManagedConfig called with sync", syncedAction === "sync", `got: ${syncedAction}`)
    check("service observed started event", started.includes("mac-workspace-service-smoke-run"), `got: ${started.join(", ")}`)
    check("service observed status event", statuses.some((entry) => entry.stage === "python-automation"), JSON.stringify(statuses))
    check("service returned assistant reply", Boolean(result.reply), JSON.stringify(result))
    check("service reply content matches", result.reply?.content?.includes("service smoke ok"), result.reply?.content)
    check("service used bundled python", result.reply?.content?.includes(pythonExe), result.reply?.content)
    check("service injected runtime dir", result.reply?.content?.includes(runtimeDir), result.reply?.content)
  } catch (error) {
    check("ProjectWorkspaceExecutorService execution", false, error instanceof Error ? error.message : String(error))
  } finally {
    rmSync(tmpRoot, { recursive: true, force: true })
  }

  emitSummary()
}

main().catch((error) => {
  console.error(error instanceof Error ? error.stack || error.message : String(error))
  process.exit(1)
})
