/**
 * Forge SDK
 * The Forge Platform contains an expanding collection of web service components that can be used with Autodesk cloud-based products or your own technologies. Take advantage of Autodesk’s expertise in design and engineering.
 *
 * Contact: forge.help@autodesk.com
 *
 * NOTE: This class is auto generated by the swagger code generator program.
 * https://github.com/swagger-api/swagger-codegen.git
 * Do not edit the class manually.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
/*jshint esversion: 9 */

module.exports = (function () {
	'use strict';

	let OAuth2 = require('./OAuth2');
	let ApiClient = require('../ApiClient');

	/**
	 * @module auth/OAuth2TwoLeggedV2
	 */

	/**
	 * Constructs a new <code>OAuth2TwoLeggedV2</code>.
	 * Inherits from OAuth2
	 * @alias module:auth/OAuth2TwoLeggedV2
	 */
	let OAuth2TwoLeggedV2 = function (clientId, clientSecret, scope, autoRefresh, apiClient) {
		const _ApiClient = apiClient || require('../ApiClient').instance;

		this.authentication = {
			tokenUrl: '/authentication/v2/token',
			revokeTokenUrl: '/authentication/v2/revoke',
			scopes: {
				'data:read': 'The application will be able to read the end user’s data within the Autodesk ecosystem.',
				'data:write': 'The application will be able to create, update, and delete data on behalf of the end user within the Autodesk ecosystem.',
				'data:create': 'The application will be able to create data on behalf of the end user within the Autodesk ecosystem.',
				'data:search': 'The application will be able to search the end user’s data within the Autodesk ecosystem.',
				'bucket:create': 'The application will be able to create an OSS bucket it will own.',
				'bucket:read': 'The application will be able to read the metadata and list contents for OSS buckets that it has access to.',
				'bucket:update': 'The application will be able to set permissions and entitlements for OSS buckets that it has permission to modify.',
				'bucket:delete': 'The application will be able to delete a bucket that it has permission to delete.',
				'code:all': 'The application will be able to author and execute code on behalf of the end user (e.g., scripts processed by the Design Automation API).',
				'account:read': 'For Product APIs, the application will be able to read the account data the end user has entitlements to.',
				'account:write': 'For Product APIs, the application will be able to update the account data the end user has entitlements to.',
				'user-profile:read': 'The application will be able to read the end user’s profile data.',
				'viewables:read': 'The application will have read access to viewable resources such as thumbnails. This scope is a subset of data:read.',
				'user:read': 'The application will be able to read the end user’s profile data, including associated products and services.',
				'user:write': 'The application will be able to create, update, and delete the end user’s profile data, including associated products and services.',
				'openid': 'The application requires this scope to generate an id_token.',

				'data:read:*': 'dynamic scope which allow client to access the specific resource',
				'*': 'dynamic scope which allow client to access all resources',
			}
		};

		for (const key in scope) {
			const match = scope[key].match(/^data:read:(urn:adsk\.[^*\\"]+)$/);
			if (match !== null) {
				this.authentication.scopes[scope[key]] = `The application will have read access to the resource with URN '${match[1]}'.`;
			}
		}

		this.authName = 'oauth2_application';
		OAuth2.call(this, clientId, clientSecret, scope, autoRefresh, _ApiClient);
	};

	// inherit from OAuth2 class
	OAuth2TwoLeggedV2.prototype = Object.create(OAuth2.prototype);

	// Set the "constructor" property to refer to OAuth2
	OAuth2TwoLeggedV2.prototype.constructor = OAuth2TwoLeggedV2;

	/**
	 * Set the credentials manually
	 * @param credentials
	 */
	OAuth2TwoLeggedV2.prototype.setCredentials = function (credentials) {
		this.credentials = credentials;
	};

	/**
	 * Get the credentials
	 */
	OAuth2TwoLeggedV2.prototype.getCredentials = function () {
		return (this.credentials);
	};

	/**
	 * Check if token is authorized
	 * @returns {boolean}
	 */
	OAuth2TwoLeggedV2.prototype.isAuthorized = function () {
		return (!!(this.credentials && this.credentials.expires_at && this.credentials.expires_at > Date.now()));
	};

	/**
	 * Check if token has expired
	 * @returns {boolean}
	 */
	OAuth2TwoLeggedV2.prototype.hasExpired = function () {
		return (!this.credentials || !this.credentials.expires_at || this.credentials.expires_at <= Date.now());
	};

	/**
	 * Check if token is about to expire
	 * @returns {boolean}
	 */
	OAuth2TwoLeggedV2.prototype.isAboutToExpire = function (threadHoldInSeconds) {
		threadHoldInSeconds = threadHoldInSeconds || 300;
		return (!this.credentials || !this.credentials.expires_at || this.credentials.expires_at - threadHoldInSeconds * 1000 < Date.now());
	};	

	/**
	 * Authorize and get a 2 legged access token
	 * @param {Object} opts Optional parameters
	 * @param {String} opts.region can be undefined, "CAN", "DEU", "GBR", "IND", "JPN", "USA", "AUS", "IRL"
	 * @return Promise
	 */
	OAuth2TwoLeggedV2.prototype.authenticate = function (opts) {
		const _this = this;
		opts = opts || {};
		return (new Promise(function (resolve, reject) {
			if (_this.authentication && _this.authentication.tokenUrl) {
				let url = _this.basePath + _this.authentication.tokenUrl;

				let body = {
					grant_type: 'client_credentials',
					scope: _this.scope,
				};

				let Authorization = _this.BasicAuthorization(_this.clientId, _this.clientSecret);

				_this.doPostRequestWithHeaders(
					url,
					body,
					{ Authorization, region: opts.region },
					(response) => {
						// add expires_at property
						let credentials = {
							...response,
							expires_at: Date.now() + response.expires_in * 1000
						};
						_this.setCredentials(credentials);
						resolve(credentials);
					},
					(errResponse) => {
						ApiClient.instance.debug('authenticate error', errResponse);
						reject(errResponse);
					});

			} else {
				ApiClient.instance.debug('tokenUrl is not defined in the authentication object');
				reject(new Error('tokenUrl is not defined in the authentication object'));
			}
		}));
	};

	/**
	 * Revoke a 2 legged access token
	 * @return Promise
	 */
	OAuth2TwoLeggedV2.prototype.revokeToken = function () {
		const _this = this;
		return (new Promise(function (resolve, reject) {
			if (_this.authentication && _this.authentication.revokeTokenUrl) {
				let url = _this.basePath + _this.authentication.revokeTokenUrl;

				let body = {
					token: _this.getCredentials().access_token,
					token_type_hint: 'access_token',
					client_id: _this.clientId,
				};

				_this.doPostRequestWithHeaders(
					url,
					body,
					{},
					() => {
						_this.setCredentials(undefined);
						resolve();
					},
					(errResponse) => {
						ApiClient.instance.debug('authenticate error', errResponse);
						reject(errResponse);
					});

			} else {
				ApiClient.instance.debug('revokeTokenUrl is not defined in the authentication object');
				reject(new Error('revokeTokenUrl is not defined in the authentication object'));
			}
		}));
	};

	return (OAuth2TwoLeggedV2);
}());