/**
 * Scaffold generator for the axint MCP server.
 *
 * Produces a ready-to-save TypeScript intent file from a small set of
 * inputs. This is the "blank canvas" AI assistants hit when a user says
 * "create a new App Intent for X" — instead of guessing, the assistant
 * calls axint.scaffold and writes the result straight to disk.
 */

import {
  LEGACY_PARAM_ALIASES,
  isPrimitiveType,
  type IRPrimitiveType,
} from "../core/types.js";

export interface ScaffoldInput {
  name: string;
  description: string;
  domain?: string;
  params?: Array<{ name: string; type: string; description: string }>;
}

/**
 * Generate a starter TypeScript intent file from the given inputs.
 * The result is valid input to `axint compile` — it uses the public
 * defineIntent() / param.* API and includes a TODO in the perform body.
 */
export function scaffoldIntent(input: ScaffoldInput): string {
  const name = toPascalCase(input.name);
  const title = humanize(name);
  const desc = sanitize(input.description);
  const domain = input.domain ? sanitize(input.domain) : undefined;

  const paramLines: string[] = [];
  const destructureNames: string[] = [];
  for (const p of input.params ?? []) {
    const type = resolveType(p.type);
    const safeName = toCamelCase(p.name);
    destructureNames.push(safeName);
    paramLines.push(
      `    ${safeName}: param.${type}(${JSON.stringify(sanitize(p.description))}),`
    );
  }

  const paramsBlock = paramLines.length > 0 ? `\n${paramLines.join("\n")}\n  ` : "";
  const destructure =
    destructureNames.length > 0 ? `{ ${destructureNames.join(", ")} }` : "_";

  const lines: string[] = [];
  lines.push(`/**`);
  lines.push(` * ${name}Intent`);
  lines.push(` *`);
  lines.push(` * ${desc}`);
  lines.push(` *`);
  lines.push(` * Generated by axint.scaffold. Edit freely, then run:`);
  lines.push(
    ` *   npx -y -p @axint/compiler axint compile src/intents/${kebab(name)}.ts`
  );
  lines.push(` */`);
  lines.push(`import { defineIntent, param } from "@axint/compiler";`);
  lines.push(``);
  lines.push(`export default defineIntent({`);
  lines.push(`  name: ${JSON.stringify(name)},`);
  lines.push(`  title: ${JSON.stringify(title)},`);
  lines.push(`  description: ${JSON.stringify(desc)},`);
  if (domain) lines.push(`  domain: ${JSON.stringify(domain)},`);
  lines.push(`  params: {${paramsBlock}},`);
  lines.push(`  perform: async (${destructure}) => {`);
  lines.push(`    // TODO: Implement ${name}`);
  lines.push(`    return { success: true };`);
  lines.push(`  },`);
  lines.push(`});`);
  lines.push(``);

  return lines.join("\n");
}

// ─── Helpers ─────────────────────────────────────────────────────────

function resolveType(raw: string): IRPrimitiveType {
  const lc = raw.toLowerCase();
  if (isPrimitiveType(lc)) return lc;
  if (lc in LEGACY_PARAM_ALIASES) return LEGACY_PARAM_ALIASES[lc];
  // Fall back to string — keeps scaffolding from throwing on unknown
  // types. Users can edit the file if they wanted something more exotic.
  return "string";
}

function toPascalCase(s: string): string {
  if (!s) return "UnnamedIntent";
  return s
    .replace(/[-_\s]+(.)?/g, (_, c) => (c ? c.toUpperCase() : ""))
    .replace(/^(.)/, (c) => c.toUpperCase());
}

function toCamelCase(s: string): string {
  const pascal = toPascalCase(s);
  return pascal.charAt(0).toLowerCase() + pascal.slice(1);
}

function humanize(pascal: string): string {
  return pascal.replace(/([A-Z])/g, " $1").trim();
}

function kebab(pascal: string): string {
  return pascal
    .replace(/([a-z])([A-Z])/g, "$1-$2")
    .replace(/\s+/g, "-")
    .toLowerCase();
}

/**
 * Keep user-provided strings safe for interpolation. We strip control
 * chars and collapse runs of whitespace — this prevents scaffold output
 * from getting garbled by rogue newlines or tabs in a description.
 */
function sanitize(s: string): string {
  return s
    .replace(/[\x00-\x1f\x7f]+/g, " ") // eslint-disable-line no-control-regex
    .replace(/\s+/g, " ")
    .trim();
}
