import path from "node:path";
import fs from "node:fs";
import { execFile } from "node:child_process";
import { createRequire } from "node:module";

const require = createRequire(import.meta.url);

const PLATFORMS: Record<string, Record<string, string>> = {
  darwin: {
    arm64: "@jackchuka/mdschema-darwin-arm64",
    x64: "@jackchuka/mdschema-darwin-x64",
  },
  linux: {
    arm64: "@jackchuka/mdschema-linux-arm64",
    x64: "@jackchuka/mdschema-linux-x64",
  },
  win32: {
    arm64: "@jackchuka/mdschema-windows-arm64",
    x64: "@jackchuka/mdschema-windows-x64",
  },
};

interface PackageJson {
  bin?: string | Record<string, string>;
}

export function getMdschemaBin(): string {
  const pkgPath = require.resolve("@jackchuka/mdschema/package.json");
  const pkgDir = path.dirname(pkgPath);

  // Resolve from mdschema's context so pnpm optionalDependencies are visible
  const mdschemaRequire = createRequire(pkgPath);
  const ext = process.platform === "win32" ? ".exe" : "";
  const pkg = PLATFORMS[process.platform]?.[process.arch];
  if (pkg) {
    try {
      return mdschemaRequire.resolve(`${pkg}/bin/mdschema${ext}`);
    } catch {
      // Platform package not installed, fall through
    }
  }

  // Fallback: locally downloaded binary from install.js
  const localBin = path.join(pkgDir, "bin", `mdschema${ext}`);
  if (fs.existsSync(localBin)) {
    return localBin;
  }

  // Last resort: cli.js wrapper (requires shebang support, won't work on Windows)
  const pkgJson = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) as PackageJson;
  const bin = typeof pkgJson.bin === "string" ? pkgJson.bin : pkgJson.bin?.mdschema;
  if (!bin) {
    throw new Error("Could not resolve mdschema binary from package.json bin field");
  }
  return path.join(pkgDir, bin);
}

export interface MdschemaResult {
  exitCode: number;
  stdout: string;
  stderr: string;
}

export function runMdschema(args: string[], cwd?: string): Promise<MdschemaResult> {
  return new Promise((resolve) => {
    execFile(
      getMdschemaBin(),
      args,
      { encoding: "utf-8", cwd, timeout: 30_000 },
      (error, stdout, stderr) => {
        if (error) {
          const execError = error as NodeJS.ErrnoException & { status?: number };
          resolve({
            exitCode: execError.code === "ENOENT" ? 127 : (execError.status ?? 1),
            stdout: stdout ?? "",
            stderr: stderr ?? "",
          });
        } else {
          resolve({ exitCode: 0, stdout: stdout ?? "", stderr: stderr ?? "" });
        }
      },
    );
  });
}
