import { getEnv } from "../env.js";
import { regEx } from "../regex.js";
import { logger } from "../../logger/index.js";
import { PLATFORM_HOST_TYPES } from "../../constants/platforms.js";
import { createURLFromHostOrURL, isHttpUrl } from "../url.js";
import { find, getAll } from "../host-rules.js";
import { detectPlatform } from "../common.js";
import { parseGitUrl } from "./url.js";
import { isEmptyString } from "@sindresorhus/is";

//#region lib/util/git/auth.ts
const githubApiUrls = new Set([
	"github.com",
	"api.github.com",
	"https://api.github.com",
	"https://api.github.com/"
]);
/**
* Add authorization to a Git Url and returns a new environment variables object
* @returns a new NodeJS.ProcessEnv object without modifying any input parameters
*/
function getGitAuthenticatedEnvironmentVariables(originalGitUrl, { token, username, password, hostType, matchHost }, environmentVariables) {
	if (!token && !(username && password)) {
		logger.warn({ host: matchHost }, `Could not create environment variable for host as neither token or username and password was set`);
		return { ...environmentVariables };
	}
	const env = getEnv();
	const gitConfigCountEnvVariable = environmentVariables?.GIT_CONFIG_COUNT ?? env.GIT_CONFIG_COUNT;
	let gitConfigCount = 0;
	if (gitConfigCountEnvVariable) {
		gitConfigCount = parseInt(gitConfigCountEnvVariable, 10);
		if (Number.isNaN(gitConfigCount)) {
			logger.warn({ GIT_CONFIG_COUNT: env.GIT_CONFIG_COUNT }, `Found GIT_CONFIG_COUNT env variable, but couldn't parse the value to an integer. Ignoring it.`);
			gitConfigCount = 0;
		}
	}
	let authenticationRules;
	if (token) authenticationRules = getAuthenticationRulesWithToken(originalGitUrl, hostType, token);
	else authenticationRules = getAuthenticationRules(originalGitUrl, hostType, `${encodeURIComponent(username)}:${encodeURIComponent(password)}`);
	const newEnvironmentVariables = { ...environmentVariables };
	for (const rule of authenticationRules) {
		newEnvironmentVariables[`GIT_CONFIG_KEY_${gitConfigCount}`] = `url.${rule.url}.insteadOf`;
		newEnvironmentVariables[`GIT_CONFIG_VALUE_${gitConfigCount}`] = rule.insteadOf;
		gitConfigCount++;
	}
	newEnvironmentVariables.GIT_CONFIG_COUNT = gitConfigCount.toString();
	return newEnvironmentVariables;
}
function getAuthenticationRulesWithToken(url, hostType, authToken) {
	let token = authToken;
	let type = hostType;
	type ??= detectPlatform(url);
	if (type === "gitlab") token = `gitlab-ci-token:${authToken}`;
	return getAuthenticationRules(url, type, token);
}
/**
* Generates the authentication rules for later git usage for the given host
* @link https://coolaj86.com/articles/vanilla-devops-git-credentials-cheatsheet/
* @param gitUrl Git repository URL
* @param hostType Git host type
* @param token Authentication token or `username:password` string
*/
function getAuthenticationRules(gitUrl, hostType, token) {
	const authenticationRules = [];
	const hasUser = token.split(":").length > 1;
	const insteadUrl = parseGitUrl(gitUrl);
	let sshPort = insteadUrl.port;
	if (hostType === "bitbucket-server") {
		insteadUrl.source = "bitbucket-server";
		// v8 ignore next -- TODO: add test #40625
		if (!sshPort || isEmptyString(sshPort)) sshPort = "7999";
	}
	const url = { ...insteadUrl };
	const protocol = regEx(/^https?$/).test(url.protocol) ? url.protocol : "https";
	url.token = hasUser ? token : `ssh:${token}`;
	authenticationRules.push({
		url: url.toString(protocol),
		insteadOf: `ssh://git@${insteadUrl.resource}${sshPort ? `:${sshPort}` : ""}/${insteadUrl.full_name}${insteadUrl.git_suffix ? ".git" : ""}`
	});
	url.token = hasUser ? token : `git:${token}`;
	authenticationRules.push({
		url: url.toString(protocol),
		insteadOf: {
			...insteadUrl,
			port: sshPort
		}.toString("ssh")
	});
	url.token = token;
	authenticationRules.push({
		url: url.toString(protocol),
		insteadOf: insteadUrl.toString(protocol)
	});
	return authenticationRules;
}
function getGitEnvironmentVariables(additionalHostTypes = []) {
	let environmentVariables = {};
	const gitHubHostRule = find({
		hostType: "github",
		url: "https://api.github.com/"
	});
	if (gitHubHostRule?.token) environmentVariables = getGitAuthenticatedEnvironmentVariables("https://github.com/", gitHubHostRule);
	const gitAllowedHostTypes = new Set([...PLATFORM_HOST_TYPES, ...additionalHostTypes]);
	const hostRules = getAll().filter((r) => r.matchHost && (r.token ?? (r.username && r.password))).filter((r) => !gitHubHostRule || !githubApiUrls.has(r.matchHost));
	for (const hostRule of hostRules) if (!hostRule.hostType || gitAllowedHostTypes.has(hostRule.hostType)) environmentVariables = addAuthFromHostRule(hostRule, environmentVariables);
	return environmentVariables;
}
function addAuthFromHostRule(hostRule, env) {
	let environmentVariables = env;
	const httpUrl = createURLFromHostOrURL(hostRule.matchHost)?.toString();
	if (isHttpUrl(httpUrl)) {
		logger.trace(`Adding Git authentication for ${httpUrl} using token auth.`);
		environmentVariables = getGitAuthenticatedEnvironmentVariables(httpUrl, hostRule, environmentVariables);
	} else logger.debug(`Could not parse registryUrl ${hostRule.matchHost} or not using http(s). Ignoring`);
	return environmentVariables;
}

//#endregion
export { getGitEnvironmentVariables };
//# sourceMappingURL=auth.js.map