type GenerateWebhookEventFunctionParams = {
  eventName: string;
  populatedType: string;
  customPrefix?: string;
  idKey?: string;
  fetchCode?: string;
};

type GenerateWebhookEventFunctionForListParams = {
  eventNames: string[];
  populatedType: string;
  customPrefix?: string;
  idKey?: string;
  fetchCode?: string;
};

/**
 * Generates a function with a name based on the event string, e.g. "record.created" -> "onRecordCreated".
 * The generated function will subscribe to that event using the webhooks client.
 *
 * @param eventName The event name string (must be a valid AttioWebhookEventType)
 * @param customPrefix Optional prefix for the function name (default is "on")
 * @param idKey The key to use for fetching the entity (optional if fetchCode is provided)
 * @param fetchCode A string of code to fetch the entity (optional, takes precedence over idKey)
 *
 * @returns A string representing the function definition
 */
export function generateWebhookEventFunction({ eventName, populatedType, customPrefix = "on", ...rest }: GenerateWebhookEventFunctionParams) {
  // Convert e.g. "record.created" to "onRecordCreated"
  const [, action] = eventName.split(".");

  if (!action) {
    throw new Error(`Invalid event name: ${eventName}. Expected format is "object.action".`);
  }

  const functionName = `${customPrefix}${action.charAt(0).toUpperCase() + action.slice(1)}`;

  const fetchDataCode =
    "fetchCode" in rest
      ? `const data = await (${rest.fetchCode});`
      : "idKey" in rest
        ? `const data = await this.getById(payload.id.${rest.idKey});`
        : `const data = undefined; // No idKey or fetchCode provided`;

  return `
  ${functionName}(listener: AttioWebhookEventPopulatedListener<WebhookEventDataByType<"${eventName}">, ${eventName.includes("deleted") ? "undefined" : populatedType}>): void {
    this.client.webhooks.on("${eventName}", async (payload: WebhookEventDataByType<"${eventName}">) => {
      ${eventName.includes("deleted") ? "const data = undefined;" : fetchDataCode}

      await listener({
        payload,
        data,
      })
    });
  }
  `.trim();
}

export function generateWebhookEventFunctionForList({ eventNames, ...options }: GenerateWebhookEventFunctionForListParams) {
  return eventNames.map((eventName) => generateWebhookEventFunction({ ...options, eventName })).join("\n\n  ");
}
