import fs from "node:fs";
import path from "node:path";

const command = process.argv[2];
const readJson = (file) => JSON.parse(fs.readFileSync(file, "utf8"));
const agentTurnTimeoutSeconds = Number.parseInt(
  process.env.OPENCLAW_LIVE_PLUGIN_TOOL_TIMEOUT_SECONDS ?? "300",
  10,
);

function requireEnv(name) {
  const value = process.env[name];
  if (!value) {
    throw new Error(`missing ${name}`);
  }
  return value;
}

function stateDir() {
  return process.env.OPENCLAW_STATE_DIR || path.join(process.env.HOME, ".openclaw");
}

function configPath() {
  return process.env.OPENCLAW_CONFIG_PATH || path.join(stateDir(), "openclaw.json");
}

function realPathMaybe(filePath) {
  try {
    return fs.realpathSync(filePath);
  } catch {
    return path.resolve(filePath);
  }
}

function assertPathInside(parentPath, childPath, label) {
  const parent = realPathMaybe(parentPath);
  const child = realPathMaybe(childPath);
  const relative = path.relative(parent, child);
  if (relative.startsWith("..") || path.isAbsolute(relative)) {
    throw new Error(`${label} resolved outside ${parentPath}: ${child}`);
  }
}

function writeJson(file, value) {
  fs.mkdirSync(path.dirname(file), { recursive: true });
  fs.writeFileSync(file, `${JSON.stringify(value, null, 2)}\n`);
}

function installRecords() {
  const indexPath = path.join(stateDir(), "plugins", "installs.json");
  const index = fs.existsSync(indexPath) ? readJson(indexPath) : {};
  const cfg = fs.existsSync(configPath()) ? readJson(configPath()) : {};
  return index.installRecords || index.records || cfg.plugins?.installs || {};
}

function pluginInstallPath() {
  const pluginId = requireEnv("PLUGIN_ID");
  const inspect = fs.existsSync("/tmp/openclaw-plugin-inspect.json")
    ? readJson("/tmp/openclaw-plugin-inspect.json")
    : {};
  const record = installRecords()[pluginId] || inspect.install;
  if (!record) {
    throw new Error(`missing ${pluginId} install record`);
  }
  if (record.source !== "npm" || record.artifactKind !== "npm-pack") {
    throw new Error(`expected npm-pack install record: ${JSON.stringify(record)}`);
  }
  return String(record.installPath || "").replace(/^~(?=$|\/)/u, process.env.HOME);
}

function writeFixture() {
  const dir = process.argv[3];
  if (!dir) {
    throw new Error("write-fixture requires output dir");
  }
  const pluginId = requireEnv("PLUGIN_ID");
  const pluginName = requireEnv("PLUGIN_NAME");
  const version = requireEnv("PLUGIN_VERSION");
  const toolName = requireEnv("TOOL_NAME");
  const seed = requireEnv("SEED");
  writeJson(path.join(dir, "package.json"), {
    name: pluginName,
    version,
    dependencies: { slugify: "^1.6.6" },
    openclaw: { extensions: ["./index.js"] },
  });
  writeJson(path.join(dir, "openclaw.plugin.json"), {
    id: pluginId,
    name: "E2E Slug Tool",
    description: "Docker E2E plugin tool fixture",
    activation: { onStartup: true },
    contracts: { tools: [toolName] },
    configSchema: { type: "object", additionalProperties: false },
  });
  fs.writeFileSync(
    path.join(dir, "index.js"),
    `const slugify = require("slugify");\n` +
      `const value = slugify(${JSON.stringify(seed)}, { lower: true, strict: true });\n` +
      `module.exports = {\n` +
      `  id: ${JSON.stringify(pluginId)},\n` +
      `  name: "E2E Slug Tool",\n` +
      `  register(api) {\n` +
      `    api.registerTool({\n` +
      `      name: ${JSON.stringify(toolName)},\n` +
      `      description: "Return the hidden Docker E2E slug generated by the plugin dependency.",\n` +
      `      parameters: { type: "object", properties: {}, additionalProperties: false },\n` +
      `      async execute() {\n` +
      `        return { content: [{ type: "text", text: value }] };\n` +
      `      },\n` +
      `    });\n` +
      `  },\n` +
      `};\n`,
  );
}

function configure() {
  const modelRef = requireEnv("MODEL_REF");
  const pluginId = requireEnv("PLUGIN_ID");
  const toolName = requireEnv("TOOL_NAME");
  const cfgPath = configPath();
  const cfg = fs.existsSync(cfgPath) ? readJson(cfgPath) : {};
  const [providerId, modelId] = modelRef.split("/");
  if (providerId !== "openai" || !modelId) {
    throw new Error(`live plugin tool E2E expects an openai/* model, got ${modelRef}`);
  }
  cfg.plugins = {
    ...cfg.plugins,
    enabled: true,
    allow: Array.from(new Set([...(cfg.plugins?.allow || []), "openai", pluginId])).toSorted(
      (left, right) => left.localeCompare(right),
    ),
    entries: {
      ...cfg.plugins?.entries,
      openai: { ...cfg.plugins?.entries?.openai, enabled: true },
      [pluginId]: { ...cfg.plugins?.entries?.[pluginId], enabled: true },
    },
  };
  cfg.tools = {
    ...cfg.tools,
    allow: [toolName],
  };
  cfg.models = {
    ...cfg.models,
    mode: "merge",
    providers: {
      ...cfg.models?.providers,
      openai: {
        ...cfg.models?.providers?.openai,
        api: "openai-responses",
        baseUrl: (process.env.OPENAI_BASE_URL || "https://api.openai.com/v1").trim(),
        apiKey: { source: "env", provider: "default", id: "OPENAI_API_KEY" },
        agentRuntime: { id: "pi" },
        timeoutSeconds: agentTurnTimeoutSeconds,
        models: [
          {
            id: modelId,
            name: modelId,
            api: "openai-responses",
            reasoning: false,
            input: ["text"],
            cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
            contextWindow: 128000,
            contextTokens: 96000,
            maxTokens: 512,
          },
        ],
      },
    },
  };
  cfg.agents = {
    ...cfg.agents,
    defaults: {
      ...cfg.agents?.defaults,
      model: { primary: modelRef, fallbacks: [] },
      models: {
        ...cfg.agents?.defaults?.models,
        [modelRef]: {
          ...cfg.agents?.defaults?.models?.[modelRef],
          agentRuntime: { id: "pi" },
          params: { transport: "sse", openaiWsWarmup: false },
        },
      },
      workspace: path.join(stateDir(), "workspace"),
      skipBootstrap: true,
      timeoutSeconds: agentTurnTimeoutSeconds,
    },
  };
  writeJson(cfgPath, cfg);
}

function findDependencyPackageJson(packageName) {
  const installPath = pluginInstallPath();
  const npmRoot = path.join(stateDir(), "npm");
  return [
    path.join(installPath, "node_modules", packageName, "package.json"),
    path.join(npmRoot, "node_modules", packageName, "package.json"),
  ].find((candidate) => fs.existsSync(candidate));
}

function assertInstalled() {
  const pluginId = requireEnv("PLUGIN_ID");
  const pluginName = requireEnv("PLUGIN_NAME");
  const toolName = requireEnv("TOOL_NAME");
  const npmRoot = path.join(stateDir(), "npm");
  const installPath = pluginInstallPath();
  assertPathInside(npmRoot, installPath, "fixture plugin install path");
  const packageJson = path.join(installPath, "package.json");
  if (!fs.existsSync(packageJson)) {
    throw new Error(`missing fixture plugin package.json: ${packageJson}`);
  }
  const pkg = readJson(packageJson);
  if (pkg.name !== pluginName) {
    throw new Error(`unexpected fixture package name: ${pkg.name}`);
  }
  const slugifyPackageJson = findDependencyPackageJson("slugify");
  if (!slugifyPackageJson) {
    throw new Error("missing slugify dependency installed by npm-pack plugin install");
  }
  assertPathInside(npmRoot, slugifyPackageJson, "slugify dependency");

  const list = readJson("/tmp/openclaw-plugins-list.json");
  const plugin = (list.plugins || []).find((entry) => entry.id === pluginId);
  if (!plugin || plugin.enabled !== true || plugin.status !== "loaded") {
    throw new Error(`fixture plugin was not enabled+loaded: ${JSON.stringify(plugin)}`);
  }
  const inspect = readJson("/tmp/openclaw-plugin-inspect.json");
  const toolNames = Array.isArray(inspect.tools)
    ? inspect.tools.flatMap((entry) => (Array.isArray(entry?.names) ? entry.names : []))
    : [];
  if (!toolNames.includes(toolName)) {
    throw new Error(`fixture tool was not registered: ${JSON.stringify(inspect.tools)}`);
  }
}

function assertAgentTurn() {
  const expected = requireEnv("EXPECTED_SLUG");
  const toolName = requireEnv("TOOL_NAME");
  const stdout = fs.readFileSync("/tmp/openclaw-agent.json", "utf8");
  const stderr = fs.existsSync("/tmp/openclaw-agent.err")
    ? fs.readFileSync("/tmp/openclaw-agent.err", "utf8")
    : "";
  const response = JSON.parse(stdout);
  const text = (response.payloads || []).map((payload) => payload?.text || "").join("\n");
  if (!text.includes(expected)) {
    throw new Error(
      `live agent reply did not contain tool slug ${expected}:\nstdout=${stdout}\nstderr=${stderr}`,
    );
  }
  const sessionsDir = path.join(stateDir(), "agents", "main", "sessions");
  const sessionFiles = fs
    .readdirSync(sessionsDir, { recursive: true })
    .map((entry) => path.join(sessionsDir, String(entry)))
    .filter((entry) => entry.endsWith(".jsonl") && fs.existsSync(entry));
  const transcript = sessionFiles.map((file) => fs.readFileSync(file, "utf8")).join("\n");
  if (!transcript.includes(toolName) || !transcript.includes(expected)) {
    throw new Error(
      `session transcript did not show ${toolName} returning ${expected}; checked ${sessionFiles.join(", ")}`,
    );
  }
}

const commands = {
  "write-fixture": writeFixture,
  configure,
  "assert-installed": assertInstalled,
  "assert-agent-turn": assertAgentTurn,
};

const fn = commands[command];
if (!fn) {
  throw new Error(`unknown live plugin tool assertion command: ${command}`);
}
fn();
