import { regEx } from "../../../util/regex.js";
import { logger } from "../../../logger/index.js";
import { ensureTrailingSlash, trimTrailingSlash } from "../../../util/url.js";
import { get, set } from "../../../util/cache/package/index.js";
import { withCache } from "../../../util/cache/package/with-cache.js";
import { Http } from "../../../util/http/index.js";
import { asTimestamp } from "../../../util/timestamp.js";
import { compare } from "../../versioning/maven/compare.js";
import { MAVEN_REPO } from "../maven/common.js";
import { downloadHttpContent, downloadHttpProtocol } from "../maven/util.js";
import { MavenDatasource } from "../maven/index.js";
import "../../versioning/ivy/index.js";
import { extractPageLinks, getLatestVersion } from "./util.js";
import upath from "upath";
import { XmlDocument } from "xmldoc";
//#region lib/modules/datasource/sbt-package/index.ts
var SbtPackageDatasource = class SbtPackageDatasource extends MavenDatasource {
	static id = "sbt-package";
	defaultRegistryUrls = [MAVEN_REPO];
	defaultVersioning = "ivy";
	registryStrategy = "hunt";
	sourceUrlSupport = "package";
	sourceUrlNote = "The source URL is determined from the `scm` tags in the results.";
	constructor(id = SbtPackageDatasource.id) {
		super(id);
		this.http = new Http("sbt");
	}
	static parseDepCoordinate(packageName) {
		const [groupId, javaArtifactId] = packageName.split(":");
		const [artifactId, scalaVersion] = javaArtifactId.split("_");
		return {
			groupId,
			artifactId,
			scalaVersion
		};
	}
	async getSbtReleases(registryUrl, packageName) {
		const { groupId, artifactId, scalaVersion } = SbtPackageDatasource.parseDepCoordinate(packageName);
		const groupIdSplit = groupId.split(".");
		const repoRootUrl = ensureTrailingSlash(registryUrl);
		const validRootUrlKey = `valid-root-url:${registryUrl}:${packageName}`;
		const validRootUrl = await get("datasource-sbt-package", validRootUrlKey);
		const packageRootUrls = [];
		// istanbul ignore if: not easily testable
		if (validRootUrl) packageRootUrls.push(validRootUrl);
		else {
			const packageRootUrlWith = (sep) => `${repoRootUrl}${groupIdSplit.join(sep)}`;
			packageRootUrls.push(ensureTrailingSlash(packageRootUrlWith("/")));
			packageRootUrls.push(ensureTrailingSlash(packageRootUrlWith(".")));
		}
		let dependencyUrl;
		let packageUrls;
		for (const packageRootUrl of packageRootUrls) {
			const packageRootContent = await downloadHttpContent(this.http, packageRootUrl);
			if (!packageRootContent) continue;
			await set("datasource-sbt-package", validRootUrlKey, packageRootUrl, 720 * 60);
			dependencyUrl = trimTrailingSlash(packageRootUrl);
			const rootPath = new URL(packageRootUrl).pathname;
			const artifactSubdirs = extractPageLinks(packageRootContent, (href) => {
				const path = href.replace(rootPath, "");
				if (path.startsWith(`${artifactId}_native`) || path.startsWith(`${artifactId}_sjs`)) return null;
				if (path === artifactId || path.startsWith(`${artifactId}_`)) return ensureTrailingSlash(`${packageRootUrl}${path}`);
				return null;
			});
			if (scalaVersion) {
				const scalaSubdir = artifactSubdirs.find((x) => x.endsWith(`/${artifactId}_${scalaVersion}/`));
				if (scalaSubdir) {
					packageUrls = [scalaSubdir];
					break;
				}
			}
			packageUrls = artifactSubdirs;
			break;
		}
		if (!packageUrls) return null;
		const invalidPackageUrlsKey = `invalid-package-urls:${registryUrl}:${packageName}`;
		const invalidPackageUrls = new Set(await get("datasource-sbt-package", invalidPackageUrlsKey));
		packageUrls = packageUrls.filter((url) => !invalidPackageUrls.has(url));
		const allVersions = /* @__PURE__ */ new Set();
		for (const pkgUrl of packageUrls) {
			const packageContent = await downloadHttpContent(this.http, pkgUrl);
			// istanbul ignore if
			if (!packageContent) {
				invalidPackageUrls.add(pkgUrl);
				continue;
			}
			const rootPath = new URL(pkgUrl).pathname;
			const versions = extractPageLinks(packageContent, (href) => {
				const path = href.replace(rootPath, "");
				if (path.startsWith(".")) return null;
				return path;
			});
			for (const version of versions) allVersions.add(version);
		}
		if (invalidPackageUrls.size > 0) await set("datasource-sbt-package", invalidPackageUrlsKey, [...invalidPackageUrls], 720 * 60);
		if (packageUrls.length > 0) await set("datasource-sbt-package", `package-urls:${registryUrl}:${packageName}`, packageUrls, 720 * 60);
		const versions = [...allVersions];
		if (!versions.length) return null;
		const res = {
			releases: [...allVersions].sort(compare).map((version) => ({ version })),
			dependencyUrl
		};
		const latestVersion = getLatestVersion(versions);
		const pomInfo = await this.getPomInfo(registryUrl, packageName, latestVersion, packageUrls);
		if (pomInfo?.homepage) res.homepage = pomInfo.homepage;
		if (pomInfo?.sourceUrl) res.sourceUrl = pomInfo.sourceUrl;
		return res;
	}
	async getPomInfo(registryUrl, packageName, version, pkgUrls) {
		const packageUrlsKey = `package-urls:${registryUrl}:${packageName}`;
		// istanbul ignore next: will be covered later
		const packageUrls = pkgUrls ?? await get("datasource-sbt-package", packageUrlsKey);
		// istanbul ignore if
		if (!packageUrls?.length) return null;
		// istanbul ignore if
		if (!version) return null;
		const invalidPomFilesKey = `invalid-pom-files:${registryUrl}:${packageName}:${version}`;
		const invalidPomFiles = new Set(await get("datasource-sbt-package", invalidPomFilesKey));
		const saveCache = async () => {
			if (invalidPomFiles.size > 0) await set("datasource-sbt-package", invalidPomFilesKey, [...invalidPomFiles], 720 * 60);
		};
		for (const packageUrl of packageUrls) {
			const artifactDir = upath.basename(packageUrl);
			const [artifact] = artifactDir.split("_");
			for (const pomFilePrefix of [artifactDir, artifact]) {
				const pomUrl = `${packageUrl}${version}/${`${pomFilePrefix}-${version}.pom`}`;
				if (invalidPomFiles.has(pomUrl)) continue;
				const { val } = (await downloadHttpProtocol(this.http, pomUrl)).unwrap();
				if (!val) {
					invalidPomFiles.add(pomUrl);
					continue;
				}
				const result = {};
				const releaseTimestamp = asTimestamp(val.lastModified);
				if (releaseTimestamp) result.releaseTimestamp = releaseTimestamp;
				const pomXml = new XmlDocument(val.data);
				const homepage = pomXml.valueWithPath("url");
				if (homepage) result.homepage = homepage;
				const sourceUrl = pomXml.valueWithPath("scm.url");
				if (sourceUrl) result.sourceUrl = sourceUrl.replace(regEx(/^scm:/), "").replace(regEx(/^git:/), "").replace(regEx(/^git@github.com:/), "https://github.com/").replace(regEx(/\.git$/), "");
				await saveCache();
				return result;
			}
		}
		await saveCache();
		return null;
	}
	async getReleases(config) {
		const { packageName, registryUrl } = config;
		// istanbul ignore if
		if (!registryUrl) return null;
		const sbtReleases = await this.getSbtReleases(registryUrl, packageName);
		if (sbtReleases) return sbtReleases;
		logger.debug(`Sbt: no versions discovered for ${packageName} listing organization root package folder, fallback to maven datasource for version discovery`);
		const mavenReleaseResult = await super.getReleases(config);
		if (mavenReleaseResult) return mavenReleaseResult;
		logger.debug(`Sbt: no versions found for "${packageName}"`);
		return null;
	}
	async _postprocessRelease(config, release) {
		/* v8 ignore next 3 -- should never happen */
		if (!config.registryUrl) return release;
		const res = await this.getPomInfo(config.registryUrl, config.packageName, release.version);
		if (res?.releaseTimestamp) release.releaseTimestamp = res.releaseTimestamp;
		return release;
	}
	postprocessRelease(config, release) {
		return withCache({
			namespace: "datasource-sbt-package",
			key: `postprocessRelease:${config.registryUrl}:${config.packageName}:${release.version}`,
			ttlMinutes: 720 * 60
		}, () => this._postprocessRelease(config, release));
	}
};
//#endregion
export { SbtPackageDatasource };

//# sourceMappingURL=index.js.map