/**
 * Copyright © Volker Schukai and all contributing authors, {{copyRightYear}}. All rights reserved.
 * Node module: @schukai/monster
 *
 * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
 * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
 *
 * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
 * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
 * For more information about purchasing a commercial license, please contact Volker Schukai.
 *
 * SPDX-License-Identifier: AGPL-3.0
 */

import { internalSymbol } from "../../constants.mjs";
import { extend } from "../../data/extend.mjs";
import { Formatter } from "../../text/formatter.mjs";
import { getGlobalFunction } from "../../types/global.mjs";
import { isInstance, isString } from "../../types/is.mjs";
import { validateObject, validateString } from "../../types/validate.mjs";
import { parseLocale } from "../locale.mjs";
import { Provider } from "../provider.mjs";
import { Translations } from "../translations.mjs";

export { Fetch };

/**
 * The fetch provider retrieves a JSON file from the given URL and returns a translation object.
 *
 * @externalExample ../../../example/i18n/providers/fetch.mjs
 * @license AGPLv3
 * @since 1.13.0
 * @copyright Volker Schukai
 * @summary A translation provider that loads locale resources from remote endpoints via fetch.
 * @see {@link https://datatracker.ietf.org/doc/html/rfc3066}
 * @tutorial i18n-locale-and-formatter
 */
class Fetch extends Provider {
	/**
	 * As options the key `fetch` can be passed. This config object is passed to the fetch method as init.
	 *
	 * The url may contain placeholders (language, script, region, variants, extlang, privateUse), so you can specify one url for all translations.
	 *
	 * ```
	 * new Fetch('https://www.example.com/assets/${language}.json')
	 * ```
	 *
	 * @param {string|URL} url
	 * @param {Object} options see {@link Monster.I18n.Providers.Fetch#defaults}
	 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/fetch}
	 */
	constructor(url, options) {
		super(options);

		if (isInstance(url, URL)) {
			url = url.toString();
		}

		if (options === undefined) {
			options = {};
		}

		validateString(url);

		/**
		 * @property {string}
		 */
		this.url = url;

		/**
		 * @private
		 * @property {Object} options
		 */
		this[internalSymbol] = extend(
			{},
			super.defaults,
			this.defaults,
			validateObject(options),
		);
	}

	/**
	 * Defaults
	 *
	 * @property {Object} fetch
	 * @property {String} fetch.method=GET
	 * @property {String} fetch.mode=cors
	 * @property {String} fetch.cache=no-cache
	 * @property {String} fetch.credentials=omit
	 * @property {String} fetch.redirect=follow
	 * @property {String} fetch.referrerPolicy=no-referrer
	 *
	 * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API}
	 */
	get defaults() {
		return extend(
			{
				fetch: {
					method: "GET", // *GET, POST, PUT, DELETE, etc.
					mode: "cors", // no-cors, *cors, same-origin
					cache: "no-cache", // *default, no-cache, reload, force-cache, only-if-cached
					credentials: "omit", // include, *same-origin, omit
					redirect: "follow", // manual, *follow, error
					referrerPolicy: "no-referrer", // no-referrer, *no-referrer-when-downgrade, origin, origin-when-cross-origin, same-origin, strict-origin, strict-origin-when-cross-origin, unsafe-url
				},
			},
			super.defaults,
		);
	}

	/**
	 *
	 * @param {Locale|string} locale
	 * @return {Promise}
	 */
	getTranslations(locale) {
		if (isString(locale)) {
			locale = parseLocale(locale);
		}

		const formatter = new Formatter(locale.getMap());

		return getGlobalFunction("fetch")(
			formatter.format(this.url),
			this.getOption("fetch", {}),
		)
			.then((response) => response.json())
			.then((data) => {
				return new Translations(locale).assignTranslations(data);
			});
	}
}
