import { type ApiMeta, type Params } from "./types.ts";

// TODO: make this dynamic
function toTypescriptType(type: string) {
  const typesMap: Record<string, string> = {
    Array: "unknown[]",
    "ArrayOf(Buffer)": "number[]",
    "ArrayOf(Dictionary)": "Record<string, unknown>[]",
    "ArrayOf(Integer)": "number[]",
    "ArrayOf(Integer, 2)": "[number, number]",
    "ArrayOf(String)": "string[]",
    "ArrayOf(Tabpage)": "number[]",
    "ArrayOf(Window)": "number[]",
    Boolean: "boolean",
    Buffer: "number",
    Dictionary: "Record<string, unknown>",
    Float: "number",
    Integer: "number",
    LuaRef: "unknown",
    Object: "unknown",
    String: "string",
    Tabpage: "number",
    void: "void",
    Window: "number",
  };

  const typescriptType = typesMap[type];
  if (!typescriptType)
    throw Error(`typescriptType for type: ${type} could not be termined`);
  return typescriptType;
}

function parseParameters(params: Params) {
  return params
    .map((param) => `${param[1]}: ${toTypescriptType(param[0])}`)
    .join(", ");
}

export function generateTypescriptContent(neovimApi: ApiMeta) {
  let output = `/* eslint @typescript-eslint/no-invalid-void-type: 0 */

/*
 * file generated by bunvim: https://github.com/gualcasas/bunvim
 */

import { type EventsMap } from "nvim-node";

export type NeovimApi<
  Notifications extends EventsMap = EventsMap,
  Requests extends EventsMap = EventsMap,
> = {\n`;
  // functions
  output += "  functions: {\n";
  neovimApi.functions.forEach((fun) => {
    output += `    ${fun.name}: {
      parameters: [${parseParameters(fun.parameters)}];
      return_type: ${toTypescriptType(fun.return_type)};\n    };\n`;
  });
  output += "  };\n\n";

  // ui_events
  output += "  ui_events: {\n";
  neovimApi.ui_events.forEach((event) => {
    output += `    ${event.name}: {\n      parameters: [${parseParameters(
      event.parameters,
    )}];\n    };\n`;
  });
  output += "  };\n\n";

  // error_types
  output += "  error_types: {\n";
  Object.entries(neovimApi.error_types).forEach(([type, { id }]) => {
    output += `    ${type}: { id: ${id}; };\n`;
  });
  output += "  };\n\n";

  // types
  output += "  types: {\n";
  Object.entries(neovimApi.types).forEach(([type, { id, prefix }]) => {
    output += `    ${type}: { id: ${id}; prefix: "${prefix}"; };\n`;
  });
  output += "  };\n\n";

  // ui_options
  output += `  ui_options: ${JSON.stringify(neovimApi.ui_options)};\n\n`;

  // custom user notifications
  output += `  notifications: Notifications;\n\n`;

  // custm user requests
  output += `  requests: Requests;\n`;

  output += "};";

  return output;
}
