/**
 * AdvancedBilling
 *
 * This file was automatically generated for Maxio by APIMATIC v3.0 ( https://www.apimatic.io ).
 */

import { HttpClientOptions } from './clientAdapter.js';
import {
  anyOf,
  array,
  boolean,
  literal,
  number,
  object,
  optional,
  Schema,
  string,
  stringEnum,
  validateAndMap,
} from './schema.js';

/** An interface for all configuration parameters required by the SDK. */
export interface Configuration {
  timeout: number;
  environment: Environment;
  site: string;
  basicAuthCredentials?: {
    username: string;
    password: string;
  };
  httpClientOptions?: Partial<HttpClientOptions>;
  unstable_httpClientOptions?: any;
}

/** Environments available for API */
export enum Environment {
  US = 'US',
  EU = 'EU',
}

export namespace Configuration {
  export function fromJsonConfig(jsonConfig: string): Partial<Configuration> {
    const configurationObject = JSON.parse(jsonConfig);
    const result = validateAndMap(jsonConfig, configurationObject);

    if (result.errors) {
      throw new Error(
        'Invalid configuration provided. Please check the following errors:\n' +
          result.errors.map((e: any) => e.message).join('\n')
      );
    }

    return result.result;
  }

  export function fromEnvironment(
    envVariables: Record<string, string | undefined>
  ): Partial<Configuration> {
    const config: any = {};

    config.timeout = envVariables.TIMEOUT;
    config.environment = envVariables.ENVIRONMENT;
    config.site = envVariables.SITE;

    if (envVariables.USERNAME && envVariables.PASSWORD) {
      config.basicAuthCredentials = {
        username: envVariables.USERNAME,
        password: envVariables.PASSWORD,
      };
    }

    config.httpClientOptions = {
      timeout: envVariables.TIMEOUT,
      retryConfig: {
        retryOnTimeout: envVariables.RETRY_ON_TIMEOUT,
        retryInterval: envVariables.RETRY_INTERVAL,
        maxNumberOfRetries: envVariables.MAX_NUMBER_OF_RETRIES,
        maximumRetryWaitTime: envVariables.MAX_RETRY_WAIT_TIME,
        backoffFactor: envVariables.RETRY_BACKOFF_FACTOR,
        httpStatusCodesToRetry: envVariables.HTTP_STATUS_CODES_TO_RETRY?.split(
          ','
        ).map((s) => s.trim()),
        httpMethodsToRetry: envVariables.HTTP_METHODS_TO_RETRY?.split(
          ','
        ).map((s) => s.trim()),
      },
    };

    if (envVariables.PROXY_ADDRESS) {
      config.httpClientOptions.proxySettings = {
        address: envVariables.PROXY_ADDRESS,
        port: envVariables.PROXY_PORT,
      };

      if (
        envVariables.PROXY_AUTH_USERNAME &&
        envVariables.PROXY_AUTH_PASSWORD
      ) {
        config.httpClientOptions.proxySettings.auth = {
          username: envVariables.PROXY_AUTH_USERNAME,
          password: envVariables.PROXY_AUTH_PASSWORD,
        };
      }
    }

    const result = validateAndMap(config, configurationSchema);

    if (result.errors) {
      throw new Error(
        'Invalid configuration provided. Please check the following errors:\n' +
          result.errors.map((e: any) => e.message).join('\n')
      );
    }

    return result.result;
  }
}

const configurationSchema: Schema<Partial<Configuration>> = object({
  timeout: ['timeout', optional(number())],
  environment: ['environment', optional(stringEnum(Environment))],
  basicAuthCredentials: [
    'basicAuthCredentials',
    optional(
      object({
        username: ['username', string()],
        password: ['password', string()],
      })
    ),
  ],
  httpClientOptions: [
    'httpClientOptions',
    optional(
      object({
        timeout: ['timeout', optional(number())],
        retryConfig: [
          'retryConfig',
          optional(
            object({
              maxNumberOfRetries: ['maxNumberOfRetries', optional(number())],
              retryOnTimeout: ['retryOnTimeout', optional(boolean())],
              retryInterval: ['retryInterval', optional(number())],
              maximumRetryWaitTime: [
                'maximumRetryWaitTime',
                optional(number()),
              ],
              backoffFactor: ['backoffFactor', optional(number())],
              httpStatusCodesToRetry: [
                'httpStatusCodesToRetry',
                optional(array(number())),
              ],
              httpMethodsToRetry: [
                'httpMethodsToRetry',
                optional(
                  array(
                    anyOf([
                      literal('GET'),
                      literal('DELETE'),
                      literal('HEAD'),
                      literal('OPTIONS'),
                      literal('POST'),
                      literal('PUT'),
                      literal('PATCH'),
                      literal('LINK'),
                      literal('UNLINK'),
                    ])
                  )
                ),
              ],
            })
          ),
        ],
        proxySettings: [
          'proxySettings',
          optional(
            object({
              address: ['address', string()],
              port: ['port', optional(number())],
              auth: [
                'auth',
                optional(
                  object({
                    username: ['username', string()],
                    password: ['password', string()],
                  })
                ),
              ],
            })
          ),
        ],
      })
    ),
  ],
  site: ['site', optional(string())],
});
