import {IBeaconNodeOptions, allNamespaces, defaultOptions} from "@lodestar/beacon-node";
import {CliCommandOptions} from "@lodestar/utils";

export const enabledAll = "*";
export const enabledAllBashFriendly = "all";

/**
 * Coerce function to transform bash-friendly 'all' to CORS spec '*'
 */
export function coerceCors(cors: string): string {
  return cors === enabledAllBashFriendly ? enabledAll : cors;
}

export type ApiArgs = {
  "api.maxGindicesInProof"?: number;
  "rest.namespace"?: string[];
  "rest.cors"?: string;
  rest: boolean;
  "rest.address"?: string;
  "rest.port": number;
  "rest.headerLimit"?: number;
  "rest.bodyLimit"?: number;
  "rest.stacktraces"?: boolean;
  "rest.swaggerUI"?: boolean;
};

export function parseArgs(args: ApiArgs): IBeaconNodeOptions["api"] {
  return {
    maxGindicesInProof: args["api.maxGindicesInProof"],
    rest: {
      api: args["rest.namespace"] as IBeaconNodeOptions["api"]["rest"]["api"],
      cors: args["rest.cors"],
      enabled: args.rest,
      address: args["rest.address"],
      port: args["rest.port"],
      headerLimit: args["rest.headerLimit"],
      bodyLimit: args["rest.bodyLimit"],
      stacktraces: args["rest.stacktraces"],
      swaggerUI: args["rest.swaggerUI"],
    },
  };
}

export const options: CliCommandOptions<ApiArgs> = {
  rest: {
    type: "boolean",
    description: "Enable/disable HTTP API",
    default: defaultOptions.api.rest.enabled,
    group: "api",
  },

  "api.maxGindicesInProof": {
    hidden: true,
    type: "number",
    description: "Limit max number of gindices in a single proof request. DoS vector protection",
    defaultDescription: String(defaultOptions.api.maxGindicesInProof),
    group: "api",
  },

  "rest.namespace": {
    type: "array",
    choices: [...allNamespaces, enabledAll, enabledAllBashFriendly],
    description: `Pick namespaces to expose for HTTP API. Set to '${enabledAllBashFriendly}' (or '${enabledAll}') to enable all namespaces`,
    defaultDescription: JSON.stringify(defaultOptions.api.rest.api),
    group: "api",
    coerce: (namespaces: string[]): string[] => {
      if (namespaces.includes(enabledAll) || namespaces.includes(enabledAllBashFriendly)) {
        return allNamespaces;
      }
      // Parse ["debug,lodestar"] to ["debug", "lodestar"]
      return namespaces.flatMap((val) => val.split(","));
    },
  },

  "rest.cors": {
    type: "string",
    description: `Configures the Access-Control-Allow-Origin CORS header for HTTP API. Use '${enabledAllBashFriendly}' to allow all origins`,
    defaultDescription: defaultOptions.api.rest.cors,
    group: "api",
    coerce: coerceCors,
  },

  "rest.address": {
    type: "string",
    description: "Set host for HTTP API",
    defaultDescription: defaultOptions.api.rest.address,
    group: "api",
  },

  "rest.port": {
    type: "number",
    description: "Set port for HTTP API",
    default: defaultOptions.api.rest.port,
    group: "api",
  },
  "rest.headerLimit": {
    hidden: true,
    type: "number",
    description: "Defines the maximum length of request headers, in bytes, the server is allowed to accept",
  },
  "rest.bodyLimit": {
    hidden: true,
    type: "number",
    description: "Defines the maximum payload, in bytes, the server is allowed to accept",
  },

  "rest.stacktraces": {
    hidden: true,
    type: "boolean",
    description: "Return stacktraces in HTTP error responses",
    group: "api",
  },

  "rest.swaggerUI": {
    type: "boolean",
    description: "Enable Swagger UI for API exploration at http://{address}:{port}/documentation",
    default: Boolean(defaultOptions.api.rest.swaggerUI),
    group: "api",
  },
};
