import { getMatches } from "../file-matching.js";
import { defineSource } from "../source.js";
import { nonEmptyString, optionalUrl, stringArray } from "../utilities/schema-primitives.js";
import { ensureArray, splitCommaSeparated } from "../utilities/template-helpers.js";
import { readFile } from "node:fs/promises";
import { resolve } from "node:path";
import is from "@sindresorhus/is";
import { z } from "zod";
import { XMLParser } from "fast-xml-parser";
//#region src/lib/sources/cinder-cinderblock-xml.ts
/**
* Source and parser for Cinder `cinderblock.xml` files.
*
* CinderBlock is a package format for the Cinder C++ creative coding framework.
* Metadata lives primarily in attributes on the `<block>` element, with child
* elements for OS support (`<supports>`) and dependencies (`<requires>`).
*
* Uses `fast-xml-parser` with attribute parsing enabled.
*/
const cinderCinderblockSchema = z.object({
	author: stringArray,
	git: optionalUrl,
	id: nonEmptyString,
	library: optionalUrl,
	license: nonEmptyString,
	name: nonEmptyString,
	requires: stringArray,
	summary: nonEmptyString,
	supports: stringArray,
	url: optionalUrl,
	version: nonEmptyString
});
/**
* Map CinderBlock OS identifiers to human-readable OS names.
*/
const OS_MAP = {
	ios: "iOS",
	linux: "Linux",
	macosx: "macOS",
	msw: "Windows"
};
/**
* Parse a `cinderblock.xml` content string into a structured object.
* Returns undefined if the XML is malformed or missing the expected structure.
*/
function parse(content) {
	const parser = new XMLParser({
		attributeNamePrefix: "@_",
		ignoreAttributes: false,
		parseTagValue: false
	});
	let data;
	try {
		const parsed = parser.parse(content);
		if (!is.plainObject(parsed)) return void 0;
		data = parsed;
	} catch {
		return;
	}
	if (!is.plainObject(data.cinder)) return void 0;
	const { cinder } = data;
	if (!is.plainObject(cinder.block)) return void 0;
	const { block } = cinder;
	return cinderCinderblockSchema.parse({
		author: splitCommaSeparated(getAttribute(block, "author")),
		git: getAttribute(block, "git"),
		id: getAttribute(block, "id"),
		library: getAttribute(block, "library") ?? getAttribute(block, "libraryUrl"),
		license: getAttribute(block, "license"),
		name: getAttribute(block, "name"),
		requires: parseDependencies(block),
		summary: getAttribute(block, "summary"),
		supports: parseOperatingSystems(block),
		url: getAttribute(block, "url"),
		version: getAttribute(block, "version")
	});
}
/**
* Get a trimmed string attribute from a parsed XML element.
* fast-xml-parser stores attributes with the `@_` prefix.
*/
function getAttribute(element, name) {
	const value = element[`@_${name}`];
	if (typeof value !== "string") return void 0;
	const trimmed = value.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
/**
* Extract deduplicated, mapped operating system names from `<supports os="...">` elements.
*/
function parseOperatingSystems(block) {
	const results = [];
	const seen = /* @__PURE__ */ new Set();
	for (const support of ensureArray(block.supports)) {
		if (!is.plainObject(support)) continue;
		const os = getAttribute(support, "os");
		if (os) {
			const mapped = OS_MAP[os.toLowerCase()] ?? os;
			if (!seen.has(mapped)) {
				seen.add(mapped);
				results.push(mapped);
			}
		}
	}
	return results;
}
/**
* Extract software dependencies from `<requires>` elements.
*/
function parseDependencies(block) {
	const results = [];
	for (const dep of ensureArray(block.requires)) {
		if (typeof dep !== "string") continue;
		const trimmed = dep.trim();
		if (trimmed.length > 0) results.push(trimmed);
	}
	return results;
}
const cinderCinderblockXmlSource = defineSource({
	async discover(context) {
		return getMatches(context.options, ["cinderblock.xml"]);
	},
	key: "cinderCinderblockXml",
	async parse(input, context) {
		const data = parse(await readFile(resolve(context.options.path, input), "utf8"));
		if (data !== void 0) return {
			data,
			source: input
		};
	},
	phase: 1
});
//#endregion
export { cinderCinderblockXmlSource };
