import Axios, { AxiosInstance } from "axios";
import type { Config{{#if securities}}, Security{{/if}} } from "../config";

const DateFormat = /^\d{4}-\d{2}-\d{2}([tT]\d{2}:\d{2}:\d{2}(Z|[+-]\d{2}:\d{2})|Z)?$/;
const reviver = (_key: string, value: any) =>
  typeof value === 'string' && DateFormat.test(value) ? new Date(value) : value;

const BASE_AXIOS = Axios.create({
  transformResponse: (data) => JSON.parse(data, reviver)
});

/**
 * AbstractConfig
 */
export class AbstractConfig {
	{{#if securities}}
	readonly #security: Security;

	/**
   * constructor
   */
	constructor(security: Security = {}) {
		this.#security = security;
	}

	{{#each securities}}
	{{#and (eq type 'http') (eq scheme 'basic')}}
	protected async security(key: "{{name}}"): Promise<{username: string; password: string;}>;
	{{else or (eq type 'oauth2') (eq type 'openIdConnect')}}
	protected async security(key: "{{name}}", scopes: string[]): Promise<string>;
	{{else}}
	protected async security(key: "{{name}}"): Promise<string>;
	{{/and}}
	{{/each}}
	protected async security(key: keyof Security{{#or (any securities 'type' 'oauth2') (any securities 'type' 'openIdConnect')}}, scopes?: string[]{{/or}}): Promise<string | {username: string; password: string;}> {
		const security = this.#security[key];
		if (!security) {
			throw new Error("Unauthorized user request.");
		} else if (security instanceof Function) {
			{{#or (any securities 'type' 'oauth2') (any securities 'type' 'openIdConnect')}}
			return scopes ? security(scopes) : security();
			{{else}}
			return security();
			{{/or}}
		}
		return security;
	}
	{{/if}}
}

/**
 * AbstractApi
 */
export class AbstractApi {
  protected axios: AxiosInstance = BASE_AXIOS;

  /**
   * constructor
   */
  constructor({axios}: Config) {
    if (axios) this.axios = axios;
  }
}
