import path from "node:path";
import { requireArg, write, writeJson } from "./common.mjs";

function writePluginManifest(file, id, extra = {}) {
  writeJson(file, { id, ...extra, configSchema: { type: "object", properties: {} } });
}

function writeFakeIsNumberPackage(dir) {
  writeJson(path.join(dir, "package.json"), {
    name: "is-number",
    version: "7.0.0",
    main: "index.js",
  });
  write(path.join(dir, "index.js"), "module.exports = (value) => typeof value === 'number';\n");
}

function writePluginDemo([dir]) {
  write(
    path.join(requireArg(dir, "dir"), "index.js"),
    'module.exports = { id: "demo-plugin", name: "Demo Plugin", description: "Docker E2E demo plugin", register(api) { api.registerTool(() => null, { name: "demo_tool" }); api.registerGatewayMethod("demo.ping", async () => ({ ok: true })); api.registerCli(() => {}, { commands: ["demo"] }); api.registerService({ id: "demo-service", start: () => {} }); }, };\n',
  );
  writePluginManifest(path.join(dir, "openclaw.plugin.json"), "demo-plugin", {
    contracts: { tools: ["demo_tool"] },
  });
}

function writePlugin([dir, id, version, method, name]) {
  for (const [value, label] of [
    [dir, "dir"],
    [id, "id"],
    [version, "version"],
    [method, "method"],
    [name, "name"],
  ]) {
    requireArg(value, label);
  }
  writeJson(path.join(dir, "package.json"), {
    name: `@openclaw/${id}`,
    version,
    openclaw: { extensions: ["./index.js"] },
  });
  write(
    path.join(dir, "index.js"),
    `module.exports = { id: ${JSON.stringify(id)}, name: ${JSON.stringify(name)}, register(api) { api.registerGatewayMethod(${JSON.stringify(method)}, async () => ({ ok: true })); }, };\n`,
  );
  writePluginManifest(path.join(dir, "openclaw.plugin.json"), id);
}

function writePluginWithVendoredDependency([dir, id, version, method, name]) {
  writePlugin([dir, id, version, method, name]);
  const packageJsonPath = path.join(dir, "package.json");
  writeJson(packageJsonPath, {
    name: `@openclaw/${id}`,
    version,
    dependencies: { "is-number": "7.0.0" },
    openclaw: { extensions: ["./index.js"] },
  });
  write(
    path.join(dir, "index.js"),
    `const isNumber = require("is-number");\nmodule.exports = { id: ${JSON.stringify(id)}, name: ${JSON.stringify(name)}, register(api) { api.registerGatewayMethod(${JSON.stringify(method)}, async () => ({ ok: isNumber(42) })); }, };\n`,
  );
  writeFakeIsNumberPackage(path.join(dir, "node_modules", "is-number"));
}

function writePluginWithCli([dir, id, version, method, name, cliRoot, cliOutput]) {
  for (const [value, label] of [
    [dir, "dir"],
    [id, "id"],
    [version, "version"],
    [method, "method"],
    [name, "name"],
    [cliRoot, "cliRoot"],
    [cliOutput, "cliOutput"],
  ]) {
    requireArg(value, label);
  }
  writeJson(path.join(dir, "package.json"), {
    name: `@openclaw/${id}`,
    version,
    dependencies: { "is-number": "file:./deps/is-number" },
    openclaw: { extensions: ["./index.js"] },
  });
  writeFakeIsNumberPackage(path.join(dir, "deps", "is-number"));
  write(
    path.join(dir, "index.js"),
    `const isNumber = require("is-number");\nmodule.exports = { id: ${JSON.stringify(id)}, name: ${JSON.stringify(name)}, register(api) { api.registerGatewayMethod(${JSON.stringify(method)}, async () => ({ ok: isNumber(42) })); api.registerCli(({ program }) => { const root = program.command(${JSON.stringify(cliRoot)}).description(${JSON.stringify(`${name} fixture command`)}); root.command("ping").description("Print fixture ping output").action(() => { console.log(${JSON.stringify(cliOutput)}); }); }, { descriptors: [{ name: ${JSON.stringify(cliRoot)}, description: ${JSON.stringify(`${name} fixture command`)}, hasSubcommands: true }] }); }, };\n`,
  );
  writePluginManifest(path.join(dir, "openclaw.plugin.json"), id);
}

function writePluginWithCliRegistryDependency([
  dir,
  id,
  version,
  method,
  name,
  cliRoot,
  cliOutput,
]) {
  for (const [value, label] of [
    [dir, "dir"],
    [id, "id"],
    [version, "version"],
    [method, "method"],
    [name, "name"],
    [cliRoot, "cliRoot"],
    [cliOutput, "cliOutput"],
  ]) {
    requireArg(value, label);
  }
  writeJson(path.join(dir, "package.json"), {
    name: `@openclaw/${id}`,
    version,
    dependencies: { "is-number": "7.0.0" },
    openclaw: { extensions: ["./index.js"] },
  });
  write(
    path.join(dir, "index.js"),
    `const isNumber = require("is-number");\nmodule.exports = { id: ${JSON.stringify(id)}, name: ${JSON.stringify(name)}, register(api) { api.registerGatewayMethod(${JSON.stringify(method)}, async () => ({ ok: isNumber(42) })); api.registerCli(({ program }) => { const root = program.command(${JSON.stringify(cliRoot)}).description(${JSON.stringify(`${name} fixture command`)}); root.command("ping").description("Print fixture ping output").action(() => { console.log(${JSON.stringify(cliOutput)}); }); }, { descriptors: [{ name: ${JSON.stringify(cliRoot)}, description: ${JSON.stringify(`${name} fixture command`)}, hasSubcommands: true }] }); }, };\n`,
  );
  writePluginManifest(path.join(dir, "openclaw.plugin.json"), id);
}

function writeClaudeBundle([root]) {
  root = requireArg(root, "root");
  writeJson(path.join(root, ".claude-plugin", "plugin.json"), { name: "claude-bundle-e2e" });
  write(
    path.join(root, "commands", "office-hours.md"),
    "---\ndescription: Help with architecture and rollout planning\n---\nAct as an engineering advisor.\n\nFocus on:\n$ARGUMENTS\n",
  );
}

function writePluginMarketplace([root]) {
  root = requireArg(root, "root");
  writeJson(path.join(root, ".claude-plugin", "marketplace.json"), {
    name: "Fixture Marketplace",
    version: "1.0.0",
    plugins: [
      {
        name: "marketplace-shortcut",
        version: "0.0.1",
        description: "Shortcut install fixture",
        source: "./plugins/marketplace-shortcut",
      },
      {
        name: "marketplace-direct",
        version: "0.0.1",
        description: "Explicit marketplace fixture",
        source: { type: "path", path: "./plugins/marketplace-direct" },
      },
    ],
  });
  writeJson(path.join(process.env.HOME, ".claude", "plugins", "known_marketplaces.json"), {
    "claude-fixtures": {
      installLocation: root,
      source: { type: "github", repo: "openclaw/fixture-marketplace" },
    },
  });
}

export const pluginCommands = {
  "plugin-demo": writePluginDemo,
  plugin: writePlugin,
  "plugin-vendored-dep": writePluginWithVendoredDependency,
  "plugin-cli": writePluginWithCli,
  "plugin-cli-registry-dep": writePluginWithCliRegistryDependency,
  "fake-is-number-package": ([dir]) => writeFakeIsNumberPackage(requireArg(dir, "dir")),
  "plugin-manifest": ([file, id]) =>
    writePluginManifest(requireArg(file, "file"), requireArg(id, "id")),
  "claude-bundle": writeClaudeBundle,
  marketplace: writePluginMarketplace,
};
