import type { PageAst } from "@wrnexus/syntax";

function member(name: string): string {
  return /^[A-Za-z_$][\w$]*$/.test(name) ? name : JSON.stringify(name);
}
function params(astParams: PageAst["runtimeFunctions"][number]["parameters"]): string {
  return astParams
    .map(
      (param) =>
        `${member(param.name)}${param.optional ? "?" : ""}: ${param.valueType ?? "unknown"}`,
    )
    .join(", ");
}

export function generateDeclarations(ast: PageAst): string {
  const inline = ast.types
    .map((body) => body.trim())
    .filter(Boolean)
    .join("\n\n");
  if (ast.kind === "global-store" || ast.kind === "page-store") {
    const state = ast.states
      .filter((entry) => entry.runtime !== "server")
      .map((entry) => `  readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`)
      .join("\n");
    const computed = ast.computed
      .map((entry) => `  readonly ${member(entry.name)}: ${entry.valueType ?? "unknown"};`)
      .join("\n");
    const actions = ast.runtimeFunctions
      .filter((fn) => fn.runtime !== "server")
      .map(
        (fn) =>
          `  ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")};`,
      )
      .join("\n");
    return `${inline ? `${inline}\n\n` : ""}export interface ${ast.name}State {\n${state}\n}\n\nexport interface ${ast.name}Computed {\n${computed}\n}\n\nexport interface ${ast.name}Actions {\n${actions}\n}\n\nexport interface ${ast.name}Instance extends ${ast.name}State, ${ast.name}Computed, ${ast.name}Actions {\n  reset(): void;\n  snapshot(): Readonly<${ast.name}State>;\n}\n\ndeclare const store: ${ast.name}Instance;\nexport default store;\n`;
  }
  const props = ast.props
    .map(
      (prop) =>
        `  readonly ${member(prop.name)}${prop.required ? "" : "?"}: ${prop.valueType ?? "unknown"};`,
    )
    .join("\n");
  const outputs = ast.outputs
    .map(
      (output) =>
        `  ${member(output.name)}(${output.payload ? `${member(output.payload.name)}${output.payload.optional ? "?" : ""}: ${output.payload.valueType}` : ""}): void;`,
    )
    .join("\n");
  const clientFunctions = ast.runtimeFunctions
    .filter((fn) => fn.runtime === "client" || fn.runtime === "shared" || fn.runtime === "legacy")
    .map(
      (fn) =>
        `  ${member(fn.name)}(${params(fn.parameters)}): ${fn.returnType ?? (fn.async ? "Promise<unknown>" : "unknown")};`,
    )
    .join("\n");
  const serverFunctions = ast.runtimeFunctions
    .filter((fn) => fn.runtime === "server")
    .map(
      (fn) =>
        `  ${member(fn.name)}(${params(fn.parameters)}): Promise<Awaited<${fn.returnType ?? "unknown"}>>;`,
    )
    .join("\n");
  return `${inline ? `${inline}\n\n` : ""}export interface ${ast.name}Props {\n${props}\n}\n\nexport interface ${ast.name}Outputs {\n${outputs}\n}\n\nexport interface ${ast.name}ClientFunctions {\n${clientFunctions}\n}\n\nexport interface ${ast.name}ServerCalls {\n${serverFunctions}\n}\n`;
}
