import { regEx } from "../../../util/regex.js";
import { detectPlatform } from "../../../util/common.js";
import { GitTagsDatasource } from "../../datasource/git-tags/index.js";
import { GithubTagsDatasource } from "../../datasource/github-tags/index.js";
import { GitlabTagsDatasource } from "../../datasource/gitlab-tags/index.js";

//#region lib/modules/manager/swift/extract.ts
const regExps = {
	wildcard: regEx(/^.*?/),
	space: regEx(/(\s+|\/\/[^\n]*|\/\*.*\*\/)+/s),
	depsKeyword: regEx(/dependencies/),
	colon: regEx(/:/),
	beginSection: regEx(/\[/),
	endSection: regEx(/],?/),
	package: regEx(/\s*.\s*package\s*\(\s*/),
	urlKey: regEx(/url/),
	stringLiteral: regEx(/"[^"]+"/),
	comma: regEx(/,/),
	from: regEx(/from/),
	rangeOp: regEx(/\.\.[.<]/),
	exactVersion: regEx(/\.\s*exact\s*\(\s*/),
	exactVersionLabel: regEx(/\s*exact:/)
};
const WILDCARD = "wildcard";
const SPACE = "space";
const DEPS = "depsKeyword";
const COLON = "colon";
const BEGIN_SECTION = "beginSection";
const END_SECTION = "endSection";
const PACKAGE = "package";
const URL_KEY = "urlKey";
const STRING_LITERAL = "stringLiteral";
const COMMA = "comma";
const FROM = "from";
const RANGE_OP = "rangeOp";
const EXACT_VERSION = "exactVersion";
const EXACT_VERSION_LABEL = "exactVersionLabel";
const searchLabels = {
	wildcard: WILDCARD,
	space: SPACE,
	depsKeyword: DEPS,
	colon: COLON,
	beginSection: BEGIN_SECTION,
	endSection: END_SECTION,
	package: PACKAGE,
	urlKey: URL_KEY,
	stringLiteral: STRING_LITERAL,
	comma: COMMA,
	from: FROM,
	rangeOp: RANGE_OP,
	exactVersion: EXACT_VERSION,
	exactVersionLabel: EXACT_VERSION_LABEL
};
function searchKeysForState(state) {
	switch (state) {
		case "dependencies": return [
			SPACE,
			COLON,
			WILDCARD
		];
		case "dependencies:": return [
			SPACE,
			BEGIN_SECTION,
			WILDCARD
		];
		case "dependencies: [": return [
			SPACE,
			PACKAGE,
			END_SECTION
		];
		case ".package(": return [
			SPACE,
			URL_KEY,
			PACKAGE,
			END_SECTION
		];
		case ".package(url": return [
			SPACE,
			COLON,
			PACKAGE,
			END_SECTION
		];
		case ".package(url:": return [
			SPACE,
			STRING_LITERAL,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName]": return [
			SPACE,
			COMMA,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName],": return [
			SPACE,
			FROM,
			STRING_LITERAL,
			RANGE_OP,
			EXACT_VERSION,
			EXACT_VERSION_LABEL,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName], .exact(": return [
			SPACE,
			STRING_LITERAL,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName], exact:": return [
			SPACE,
			STRING_LITERAL,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName], from": return [
			SPACE,
			COLON,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName], from:": return [
			SPACE,
			STRING_LITERAL,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName], [value]": return [
			SPACE,
			RANGE_OP,
			PACKAGE,
			END_SECTION
		];
		case ".package(url: [depName], [rangeFrom][rangeOp]": return [
			SPACE,
			STRING_LITERAL,
			PACKAGE,
			END_SECTION
		];
		default: return [DEPS];
	}
}
function getMatch(str, state) {
	const keys = searchKeysForState(state);
	let result = null;
	for (const key of keys) {
		const regex = regExps[key];
		const label = searchLabels[key];
		const match = regex.exec(str);
		if (match) {
			const idx = match.index;
			const substr = match[0];
			const len = substr.length;
			if (idx === 0) return {
				idx,
				len,
				label,
				substr
			};
			if (!result || idx < result.idx) result = {
				idx,
				len,
				label,
				substr
			};
		}
	}
	return result;
}
function parseUrl(url) {
	// istanbul ignore if
	if (!url) return null;
	try {
		const { host, pathname, protocol } = new URL(url);
		const platform = detectPlatform(url);
		if (platform === "github" || platform === "gitlab") {
			const depName = pathname.replace(regEx(/^\//), "").replace(regEx(/\.git$/), "").replace(regEx(/\/$/), "");
			const datasource = platform === "github" ? GithubTagsDatasource.id : GitlabTagsDatasource.id;
			if (!(host === "github.com") && !(host === "gitlab.com")) return {
				depName,
				datasource,
				registryUrls: [`${protocol}//${host}`]
			};
			return {
				depName,
				datasource
			};
		}
		return {
			depName: url,
			datasource: GitTagsDatasource.id
		};
	} catch {
		return null;
	}
}
function extractPackageFile(content) {
	if (!content) return null;
	const deps = [];
	const result = { deps };
	let restStr = content;
	let state = null;
	let match = getMatch(restStr, state);
	let packageName = null;
	let currentValue = null;
	function yieldDep() {
		// istanbul ignore if
		if (!packageName) return;
		const parsedUrl = parseUrl(packageName);
		if (parsedUrl && currentValue) {
			const { depName, datasource, registryUrls } = parsedUrl;
			const dep = {
				datasource,
				depName,
				currentValue,
				...registryUrls?.length && { registryUrls }
			};
			deps.push(dep);
		}
		packageName = null;
		currentValue = null;
	}
	while (match) {
		const { idx, len, label, substr } = match;
		switch (state) {
			case null:
				if (deps.length) break;
				if (label === DEPS) state = "dependencies";
				break;
			case "dependencies":
				if (label === COLON) state = "dependencies:";
				else if (label !== SPACE) state = null;
				break;
			case "dependencies:":
				if (label === BEGIN_SECTION) state = "dependencies: [";
				else if (label !== SPACE) state = null;
				break;
			case "dependencies: [":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === URL_KEY) state = ".package(url";
				else if (label === PACKAGE) yieldDep();
				break;
			case ".package(url":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === COLON) state = ".package(url:";
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url:":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === STRING_LITERAL) {
					packageName = substr.replace(regEx(/^"/), "").replace(regEx(/"$/), "");
					state = ".package(url: [depName]";
				} else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName]":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === COMMA) state = ".package(url: [depName],";
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName],":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === FROM) {
					currentValue = substr;
					state = ".package(url: [depName], from";
				} else if (label === STRING_LITERAL) {
					currentValue = substr;
					state = ".package(url: [depName], [value]";
				} else if (label === RANGE_OP) {
					currentValue = substr;
					state = ".package(url: [depName], [rangeFrom][rangeOp]";
				} else if (label === EXACT_VERSION) state = ".package(url: [depName], .exact(";
				else if (label === EXACT_VERSION_LABEL) state = ".package(url: [depName], exact:";
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName], .exact(":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === STRING_LITERAL) {
					currentValue = substr.slice(1, substr.length - 1);
					yieldDep();
				} else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName], exact:":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === STRING_LITERAL) {
					currentValue = substr.slice(1, substr.length - 1);
					yieldDep();
					state = "dependencies: [";
				} else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName], from":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === COLON) {
					currentValue += substr;
					state = ".package(url: [depName], from:";
				} else if (label === SPACE) currentValue += substr;
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName], from:":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === STRING_LITERAL) {
					currentValue += substr;
					yieldDep();
					state = "dependencies: [";
				} else if (label === SPACE) currentValue += substr;
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName], [value]":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === RANGE_OP) {
					currentValue += substr;
					state = ".package(url: [depName], [rangeFrom][rangeOp]";
				} else if (label === SPACE) currentValue += substr;
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
			case ".package(url: [depName], [rangeFrom][rangeOp]":
				if (label === END_SECTION) {
					yieldDep();
					state = null;
				} else if (label === STRING_LITERAL) {
					currentValue += substr;
					state = "dependencies: [";
				} else if (label === SPACE) currentValue += substr;
				else if (label === PACKAGE) {
					yieldDep();
					state = ".package(";
				}
				break;
		}
		restStr = restStr.slice(idx + len);
		match = getMatch(restStr, state);
	}
	return deps.length ? result : null;
}

//#endregion
export { extractPackageFile };
//# sourceMappingURL=extract.js.map