import { regEx } from "../../../util/regex.js";
import { coerceString } from "../../../util/string.js";
import { logger } from "../../../logger/index.js";
import { isHttpUrl } from "../../../util/url.js";
import { withCache } from "../../../util/cache/package/with-cache.js";
import { asTimestamp } from "../../../util/timestamp.js";
import { id } from "../../versioning/hashicorp/index.js";
import { TerraformDatasource } from "./base.js";
import { createSDBackendURL } from "./utils.js";

//#region lib/modules/datasource/terraform-module/index.ts
var TerraformModuleDatasource = class TerraformModuleDatasource extends TerraformDatasource {
	static id = "terraform-module";
	constructor() {
		super(TerraformModuleDatasource.id);
	}
	defaultRegistryUrls = ["https://registry.terraform.io"];
	defaultVersioning = id;
	releaseTimestampSupport = true;
	releaseTimestampNote = "The release timestamp is only supported for the latest version, and is determined from the `published_at` field in the results.";
	sourceUrlSupport = "package";
	sourceUrlNote = "The source URL is determined from the the `source` field in the results.";
	extendedApiRegistryUrls = ["https://registry.terraform.io", "https://app.terraform.io"];
	/**
	* This function will fetch a package from the specified Terraform registry and return all semver versions.
	*  - `sourceUrl` is supported if "source" field is set
	*  - `homepage` is set to the Terraform registry's page if it's on the official main registry
	*/
	async _getReleases({ packageName, registryUrl }) {
		/* v8 ignore next 3 -- should never happen */
		if (!registryUrl) return null;
		const { registry: registryUrlNormalized, repository } = TerraformModuleDatasource.getRegistryRepository(packageName, registryUrl);
		logger.trace({
			registryUrlNormalized,
			terraformRepository: repository
		}, "terraform-module.getReleases()");
		const serviceDiscovery = await this.getTerraformServiceDiscoveryResult(registryUrlNormalized);
		if (this.extendedApiRegistryUrls.includes(registryUrlNormalized)) return await this.queryRegistryExtendedApi(serviceDiscovery, registryUrlNormalized, repository);
		return await this.queryRegistryVersions(serviceDiscovery, registryUrlNormalized, repository);
	}
	getReleases(config) {
		return withCache({
			namespace: `datasource-${TerraformModuleDatasource.id}`,
			key: TerraformModuleDatasource.getCacheKey(config),
			fallback: true
		}, () => this._getReleases(config));
	}
	/**
	* this uses the api that terraform registry has in addition to the base api
	* this endpoint provides more information, such as release date
	* https://www.terraform.io/registry/api-docs#latest-version-for-a-specific-module-provider
	*/
	async queryRegistryExtendedApi(serviceDiscovery, registryUrl, repository) {
		let res;
		let pkgUrl;
		try {
			pkgUrl = createSDBackendURL(registryUrl, "modules.v1", serviceDiscovery, repository);
			res = (await this.http.getJsonUnchecked(pkgUrl)).body;
			if (res.namespace + "/" + res.name + "/" + res.provider !== repository) {
				logger.warn({ pkgUrl }, "Terraform registry result mismatch");
				return null;
			}
		} catch (err) {
			this.handleGenericErrors(err);
		}
		const dep = { releases: res.versions.map((version) => ({ version })) };
		if (res.source) dep.sourceUrl = res.source;
		dep.homepage = `${registryUrl}/modules/${repository}`;
		const latestVersion = dep.releases.find((release) => res.version === release.version);
		if (latestVersion) latestVersion.releaseTimestamp = asTimestamp(res.published_at);
		return dep;
	}
	/**
	* this version uses the Module Registry Protocol that all registries are required to implement
	* https://www.terraform.io/internals/module-registry-protocol
	*/
	async queryRegistryVersions(serviceDiscovery, registryUrl, repository) {
		let res;
		let pkgUrl;
		try {
			pkgUrl = createSDBackendURL(registryUrl, "modules.v1", serviceDiscovery, `${repository}/versions`);
			res = (await this.http.getJsonUnchecked(pkgUrl)).body;
			if (res.modules.length < 1) {
				logger.warn({ pkgUrl }, "Terraform registry result mismatch");
				return null;
			}
		} catch (err) {
			this.handleGenericErrors(err);
		}
		const dep = { releases: res.modules[0].versions.map(({ version }) => ({ version })) };
		if (isHttpUrl(res.modules[0].source)) dep.sourceUrl = res.modules[0].source;
		return dep;
	}
	static getRegistryRepository(packageName, registryUrl) {
		let registry;
		const split = packageName.split("/");
		if (split.length > 3 && split[0].includes(".")) {
			[registry] = split;
			split.shift();
		} else registry = coerceString(registryUrl);
		if (!regEx(/^https?:\/\//).test(registry)) registry = `https://${registry}`;
		const repository = split.join("/");
		return {
			registry,
			repository
		};
	}
	static getCacheKey({ packageName, registryUrl }) {
		const { registry, repository } = TerraformModuleDatasource.getRegistryRepository(packageName, registryUrl);
		return `${registry}/${repository}`;
	}
};

//#endregion
export { TerraformModuleDatasource };
//# sourceMappingURL=index.js.map