#!/usr/bin/env node
/**
 * Stdin/stdout CLI for the creator UI texture API.
 *
 *   echo '{"mode":"guide","recipe":{...}}' | tsx src/texture/cli.ts
 *   echo '{"mode":"texture","force":true,"recipe":{...}}' | tsx src/texture/cli.ts
 *   echo '{"mode":"texture","albedoBase64":"...","recipe":{...}}' | tsx src/texture/cli.ts
 *
 * Prints one JSON line: { ok, glbBase64, guidePath, albedoPath, ... }
 */
import { readFile } from "node:fs/promises";
import { dirname, join, resolve } from "node:path";
import { fileURLToPath } from "node:url";
import type { CharacterRecipe } from "../creator/types.js";
import { textureCharacter } from "./textureCharacter.js";

const ROOT = resolve(fileURLToPath(new URL("../../..", import.meta.url)));
const OUT_DIR = join(ROOT, "assets", "characters");

async function readStdin(): Promise<string> {
  const chunks: Buffer[] = [];
  for await (const chunk of process.stdin) chunks.push(chunk as Buffer);
  return Buffer.concat(chunks).toString("utf8");
}

async function main(): Promise<void> {
  const raw = await readStdin();
  const payload = JSON.parse(raw) as {
    recipe?: CharacterRecipe;
    mode?: "guide" | "texture";
    force?: boolean;
    /** Import this albedo instead of generating one (PNG/JPEG, base64). */
    albedoBase64?: string;
  };
  if (!payload.recipe?.id || !payload.recipe.name || !payload.recipe.body) {
    console.log(JSON.stringify({ ok: false, error: "Expected { recipe, mode }" }));
    process.exit(1);
  }

  const imported = payload.albedoBase64
    ? new Uint8Array(Buffer.from(payload.albedoBase64, "base64"))
    : undefined;
  // An imported albedo is a texture run by definition — there is nothing to ask
  // Grok for, but the caller still wants a textured GLB back.
  const mode = payload.mode === "texture" || imported ? "texture" : "guide";
  const result = await textureCharacter(payload.recipe, {
    outDir: OUT_DIR,
    guideOnly: mode === "guide",
    force: payload.force === true,
    ...(imported ? { importAlbedo: imported } : {}),
  });

  const { writeFile, mkdir } = await import("node:fs/promises");
  await mkdir(OUT_DIR, { recursive: true });
  const glbPath = join(OUT_DIR, `${payload.recipe.id}.glb`);
  await writeFile(glbPath, result.glb);
  await writeFile(
    join(OUT_DIR, `${payload.recipe.id}.recipe.json`),
    `${JSON.stringify({ ...payload.recipe, stats: result.assembled.stats, textured: result.textured }, null, 2)}\n`,
  );

  console.log(
    JSON.stringify({
      ok: true,
      mode,
      forced: payload.force === true,
      textured: result.textured,
      imported: result.imported,
      cached: result.cached,
      costUsd: result.costUsd,
      guidePath: result.guidePath,
      albedoPath: result.albedoPath,
      glbPath,
      glbBase64: Buffer.from(result.glb).toString("base64"),
      guideUrl: `/assets-characters/${payload.recipe.id}.uv-guide.png?t=${Date.now()}`,
      albedoUrl: result.albedoPath
        ? `/assets-characters/${payload.recipe.id}.albedo.png?t=${Date.now()}`
        : null,
      bytes: result.glb.byteLength,
    }),
  );
}

main().catch((error: unknown) => {
  const message = error instanceof Error ? error.message : String(error);
  console.log(JSON.stringify({ ok: false, error: message }));
  process.exit(1);
});

void dirname;
