{{>header}}

import { Configuration } from "./configuration";
import { BASE_PATH, COLLECTION_FORMATS, encodeURIPathSegment, FetchAPI, FetchArgs, BaseAPI, RequiredError, defaultFetch } from "./runtime";
import { {{apiNamespace}} } from "./models";
{{#ifeq dateApproach 'blind-date'}}
import { LocalDateString, LocalTimeString, LocalDateTimeString, OffsetDateTimeString } from 'blind-date';
{{/ifeq}}
{{>hooks/apiImports}}

export type FactoryFunction<T> = (configuration?: Configuration, basePath?: string, fetch?: FetchAPI) => T;

{{#each groups}}
/**
 * {{className name}}Api - fetch parameter creator
 * @export
 */
export const {{className name}}ApiFetchParamCreator = function (configuration?: Configuration) {
	return {
	{{#each operations}}
		{{>frag/operationDocumentation}}
		{{identifier name}}({{#each parameters}}{{>frag/parameter}}, {{/each}}{{#if requestBody.nativeType}}{{#with requestBody}}{{>frag/parameter}}, {{/with}}{{/if}}options: RequestInit = {}): FetchArgs {
	{{#each parameters}}
	{{>frag/validateParameter operation=..}}
	{{/each}}
	{{#with requestBody}}
	{{>frag/validateParameter operation=..}}
	{{/with}}
			let localVarPath = `{{{../path}}}{{{path}}}`{{#each pathParams}}
				.replace('{{safe '{'}}{{{serializedName}}}{{safe '}'}}', encodeURIPathSegment(String({{identifier name}}))){{/each}};
			const localVarPathQueryStart = localVarPath.indexOf("?");
			const localVarRequestOptions: RequestInit = Object.assign({ method: '{{httpMethod}}' }, options);
			const localVarHeaderParameter: Headers = options.headers ? new Headers(options.headers) : new Headers();
			const localVarQueryParameter = new URLSearchParams(localVarPathQueryStart !== -1 ? localVarPath.substring(localVarPathQueryStart + 1) : "");
			if (localVarPathQueryStart !== -1) {
				localVarPath = localVarPath.substring(0, localVarPathQueryStart);
			}
	{{#if formParams}}
			const localVarFormParams = new URLSearchParams();
	{{/if}}
	{{#if cookieParams}}
			const localVarCookieParams = new URLSearchParams();
	{{/if}}

	{{#if securityRequirements}}
		{{#each securityRequirements.requirements}}
			{{#each schemes}}
			// authentication {{scheme.name}} required
			{{#if scheme.isApiKey}}
			{{#if scheme.isInHeader}}
			if (configuration && configuration.apiKey) {
				const localVarApiKeyValue = typeof configuration.apiKey === 'function'
					? configuration.apiKey({{{stringLiteral scheme.name}}})
					: configuration.apiKey;
				if (localVarApiKeyValue !== null) {
					localVarHeaderParameter.set({{{stringLiteral scheme.paramName}}}, localVarApiKeyValue);
				}
			}
			{{/if}}
			{{#if scheme.isInQuery}}
			if (configuration && configuration.apiKey) {
				const localVarApiKeyValue = typeof configuration.apiKey === 'function'
					? configuration.apiKey({{{stringLiteral scheme.name}}})
					: configuration.apiKey;
				if (localVarApiKeyValue !== null) {
					localVarQueryParameter.set({{{stringLiteral scheme.paramName}}}, localVarApiKeyValue);
				}
			}
			{{/if}}
			{{/if}}
			{{#if scheme.isBasic}}
			// http basic authentication required
			if (configuration && (configuration.username || configuration.password)) {
				localVarHeaderParameter.set("Authorization", "Basic " + btoa(configuration.username + ":" + configuration.password));
			}
			{{/if}}
			{{#or scheme.isOAuth scheme.isOpenIdConnect}}
			// oauth or openIdConnect required
			if (configuration && configuration.authorization) {
				const localVarAuthorizationValue = typeof configuration.authorization === 'function'
					? configuration.authorization({{{stringLiteral scheme.name}}}, [{{#each scopes}}{{{stringLiteral name}}}{{#unless @last}}, {{/unless}}{{/each}}])
					: configuration.authorization;
				if (localVarAuthorizationValue !== null) {
					localVarHeaderParameter.set("Authorization", "Bearer " + localVarAuthorizationValue);
				}
			}
			{{/or}}
			{{#if scheme.isHttp}}
			// http authorization required
			if (configuration && configuration.authorization) {
				const localVarAuthorizationValue = typeof configuration.authorization === 'function'
					? configuration.authorization({{{stringLiteral scheme.name}}})
					: configuration.authorization;
				if (localVarAuthorizationValue !== null) {
					localVarHeaderParameter.set("Authorization", "{{capitalize scheme.scheme}} " + localVarAuthorizationValue);
				}
			}
			{{/if}}
			{{/each}}
		{{/each}}
	{{/if}}
	{{#each queryParams}}
			{{>frag/requestParameter dest='localVarQueryParameter' var=(identifier name) encoding=encoding}}

	{{/each}}
	{{#each headerParams}}
			{{>frag/requestParameter dest='localVarHeaderParameter' var=(identifier name) encoding=encoding}}

	{{/each}}
	{{#if formParams}}
	{{#each formParams}}
			{{>frag/requestParameter dest='localVarFormParams' var=(identifier name) encoding=encoding}}

	{{/each}}
			localVarHeaderParameter.set('Content-Type', 'application/x-www-form-urlencoded');

	{{/if}}
	{{#if cookieParams}}
	{{#each cookieParams}}
			{{>frag/requestParameter dest='localVarCookieParams' var=(identifier name) encoding=encoding}}

	{{/each}}
			/* NB: setting Cookies does not work in a browser, see https://developer.mozilla.org/en-US/docs/Glossary/Forbidden_header_name */
			localVarHeaderParameter.set("Cookie", localVarCookieParams.toString().replace(/&/g, "; "));

	{{/if}}
	{{#with requestBody}}
			{{#unless consumes}}
			localVarHeaderParameter.set('Content-Type', 'application/json');
			{{/unless}}
			{{#each consumes}}
			{{#if @first}}
			localVarHeaderParameter.set('Content-Type', '{{{mediaType}}}');
			{{/if}}
			{{/each}}

	{{/with}}
			localVarRequestOptions.headers = localVarHeaderParameter;
	{{#if formParams}}
			localVarRequestOptions.body = localVarFormParams.toString();
	{{/if}}
	{{#if requestBody.nativeType}}
	{{#with requestBody}}
	
			if ({{identifier name}} !== undefined) {
		{{#with defaultContent}}
			{{#if (isContentFormUrlEncoded .)}}
				const localVarFormParams = new URLSearchParams();
				{{#each (allProperties schema)}}
				{{>frag/requestParameter dest='localVarFormParams' var=(concat (identifier ../../name) '["' serializedName '"]') encoding=(lookup ../encoding.properties name)}}
				{{/each}}
				localVarRequestOptions.body = localVarFormParams;
			{{else if (isContentJson .)}}
				localVarRequestOptions.body = JSON.stringify({{identifier ../name}} || {});
			{{else if (isContentMultipart .)}}
				const localVarFormData = new FormData();
			{{#each encoding.properties}}
				if ({{identifier ../../name}}[{{{stringLiteral property.serializedName}}}] !== undefined) {
{{#if (isArray property)}}
					for (const __anObject of {{identifier ../../name}}.{{identifier property.name}}{{#if property.nullable}} || []{{/if}}) {
						{{>frag/multipartProperty . propertyVar='__anObject' bodyPartsVar='localVarFormData'}}
					}
{{else}}
					{{>frag/multipartProperty . propertyVar=(concat (identifier ../../name) '[' (stringLiteral property.serializedName) ']') bodyPartsVar='localVarFormData'}}
{{/if}}
				}
			{{/each}}
				localVarRequestOptions.body = localVarFormData;
			{{else}}
				localVarRequestOptions.body = {{identifier ../name}};
{{/if}}
			}
		{{/with}}
	{{/with}}
	{{/if}}

			const localVarQueryParameterString = localVarQueryParameter.toString();
			if (localVarQueryParameterString) {
				localVarPath += "?" + localVarQueryParameterString;
			}
			return {
				url: localVarPath,
				options: localVarRequestOptions,
			};
		},
	{{/each}}
	}
};

/**
 * {{className name}}Api - functional programming interface
 * @export
 */
export const {{className name}}ApiFp = function(configuration?: Configuration) {
	return {
	{{#each operations}}
		{{>frag/operationDocumentation}}
		{{identifier name}}({{#each parameters}}{{>frag/parameter}}, {{/each}}{{#if requestBody.nativeType}}{{#with requestBody}}{{>frag/parameter}}, {{/with}}{{/if}}options?: RequestInit): (fetch?: FetchAPI, basePath?: string) => Promise<{{#if returnNativeType.serializedType}}{{{returnNativeType}}}{{else}}Response{{/if}}> {
			const localVarFetchArgs = {{className ../name}}ApiFetchParamCreator(configuration).{{identifier name}}({{#each parameters}}{{identifier name}}, {{/each}}{{#if requestBody.nativeType}}{{#with requestBody}}{{identifier name}}, {{/with}}{{/if}}options);
			return (fetch: FetchAPI = defaultFetch, basePath: string = BASE_PATH) => {
				return fetch(basePath + localVarFetchArgs.url, localVarFetchArgs.options).then((response) => {
					const contentType = response.headers.get('Content-Type');
					const mimeType = contentType ? contentType.replace(/;.*/, '') : undefined;
					
					{{#each responses}}
					{{#unless isCatchAll}}
					if (response.status === {{code}}) {
						{{#if contents}}
						{{#each contents}} 
						if (mimeType === {{{stringLiteral mediaType.mimeType}}}) {
							{{#if ../isDefault}}
							{{#unless schema}}
							return response; /* No schema */
							{{else}}
							{{>frag/apiResponseContent}}
							{{/unless}}
							{{else}}
							throw response;
							{{/if}}
						}
						{{/each}}
						throw response;
						{{else}}
						return response;
						{{/if}}
					}
					{{/unless}}
					{{/each}}
					{{#if catchAllResponse}}
					/* Catch-all response */
					{{#with catchAllResponse}}
					{{#if contents}}
					{{#each contents}} 
					if (mimeType === {{{stringLiteral mediaType.mimeType}}}) {
						{{#if ../isDefault}}
						{{#unless schema}}
						return response; /* No schema */
						{{else}}
						{{>frag/apiResponseContent}}
						{{/unless}}
						{{else}}
						throw response;
						{{/if}}
					}
					{{/each}}
					throw response;
					{{else}}
					return response;
					{{/if}}
					{{/with}}
					{{else}}
					throw response;
					{{/if}}
				});
			};
		},
	{{/each}}
	}
};

/**
 * {{className name}}Api - factory interface
 * @export
 */
export const {{className name}}ApiFactory: FactoryFunction<{{className name}}Api{{#if @root.withInterfaces}}Interface{{/if}}> = function (configuration?: Configuration, basePath?: string, fetch?: FetchAPI) {
	return new {{className name}}Api(configuration, basePath, fetch);
};

{{#if @root.withInterfaces}}
/**
 * {{className name}}Api - interface
 * @export
 * @interface {{className name}}Api
 */
export interface {{className name}}ApiInterface {
{{#each operations}}
	{{>frag/operationDocumentation}}
	{{identifier name}}({{#each parameters}}{{identifier name}}: {{{nativeType}}}{{#unless required}} | undefined{{/unless}}, {{/each}}options?: RequestInit): Promise<{{#if returnNativeType}}{{{returnNativeType}}}{{else}}{}{{/if}}>;

{{/each}}
}

{{/if}}
/**
 * {{className name}}Api - object-oriented interface
 * @export
 * @class {{className name}}Api
 * @extends {BaseAPI}
 */
{{#if @root.withInterfaces}}
export class {{className name}}Api extends BaseAPI implements {{className name}}ApiInterface {
{{else}}
export class {{className name}}Api extends BaseAPI {
{{/if}}
	{{#each operations}}
	{{>frag/operationDocumentation}}
	public {{identifier name}}({{#each parameters}}{{>frag/parameter}}, {{/each}}{{#if requestBody.nativeType}}{{#with requestBody}}{{>frag/parameter}}, {{/with}}{{/if}}options?: RequestInit) {
		return {{className ../name}}ApiFp(this.configuration).{{identifier name}}({{#each parameters}}{{identifier name}}, {{/each}}{{#if requestBody.nativeType}}{{#with requestBody}}{{identifier name}}, {{/with}}{{/if}}options)(this.fetch, this.basePath);
	}

	{{/each}}
}
{{/each}}

/**
 * We sometimes represent dates as strings (in models) and as Dates (in parameters) so this
 * function converts them both to a string.
 */
function dateToString(value: Date | string): string

/**
 * We sometimes represent dates as strings (in models) and as Dates (in parameters) so this
 * function converts them both to a string.
 */
function dateToString(value: Date | string | undefined): string | undefined {
	if (value instanceof Date) {
		return value.toISOString();
	} else if (typeof value === 'string') {
		return value;
	} else {
		return undefined;
	}
}
