import { getMatches } from "../file-matching.js";
import { defineSource } from "../source.js";
import { nonEmptyString, optionalUrl, parseJsonRecord, stringArray } from "../utilities/schema-primitives.js";
import { 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 { parse } from "yaml";
//#region src/lib/sources/metadata-file.ts
/**
* Source and parser for custom `metadata.json` / `metadata.yaml` / `metadata.yml` files.
*
* This is a simple custom format with synonymous field names for common
* project metadata. It supports JSON and YAML formats.
*
* Field mapping (with fallback chains):
*   description                                        → description
*   homepage | url | repository (normalized) | website → homepage
*   keywords | tags | topics                           → keywords
*   repository (normalized)                            → repository
*/
const metadataSchema = z.object({
	description: nonEmptyString,
	homepage: optionalUrl,
	keywords: stringArray,
	repository: optionalUrl
});
/**
* Parse a metadata file content string into a structured object.
* The `format` parameter determines whether to parse as JSON or YAML.
* Returns undefined if the content is malformed or not an object.
*/
function parse$1(content, format) {
	let data;
	if (format === "json") data = parseJsonRecord(content);
	else try {
		const parsed = parse(content);
		data = is.plainObject(parsed) ? parsed : void 0;
	} catch {
		return;
	}
	if (data === void 0) return;
	const repository = isString(data.repository) ? normalizeRepoUrl(data.repository) : void 0;
	const homepage = nonEmpty(data.homepage) ?? nonEmpty(data.url) ?? repository ?? nonEmpty(data.website);
	const keywords = parseKeywords(data.keywords) ?? parseKeywords(data.tags) ?? parseKeywords(data.topics) ?? [];
	return metadataSchema.parse({
		description: data.description,
		homepage,
		keywords,
		repository
	});
}
/** Return a trimmed string if the value is a non-empty string, else undefined. */
function nonEmpty(value) {
	if (typeof value !== "string") return void 0;
	const trimmed = value.trim();
	return trimmed.length > 0 ? trimmed : void 0;
}
/** Type guard for strings. */
function isString(value) {
	return typeof value === "string";
}
/** Normalize a repository URL by stripping git+ prefix and .git suffix. */
function normalizeRepoUrl(url) {
	let normalized = url;
	if (normalized.startsWith("git+")) normalized = normalized.slice(4);
	if (normalized.endsWith(".git")) normalized = normalized.slice(0, -4);
	return normalized;
}
/** Parse keywords from an array of strings or a comma-delimited string. */
function parseKeywords(value) {
	if (typeof value === "string") {
		const parsed = splitCommaSeparated(value);
		return parsed.length > 0 ? parsed : void 0;
	}
	if (Array.isArray(value)) {
		const strings = value.filter((v) => typeof v === "string");
		return strings.length > 0 ? strings : void 0;
	}
}
/** Determine the format of a metadata file by its extension. */
function getFormat(file) {
	if (file.endsWith(".json")) return "json";
	if (file.endsWith(".yaml") || file.endsWith(".yml")) return "yaml";
}
const metadataFileSource = defineSource({
	async discover(context) {
		return getMatches(context.options, [
			"metadata.json",
			"metadata.yaml",
			"metadata.yml"
		]);
	},
	key: "metadataFile",
	async parse(input, context) {
		const format = getFormat(input);
		if (format !== void 0) {
			const data = parse$1(await readFile(resolve(context.options.path, input), "utf8"), format);
			if (data !== void 0) return {
				data,
				source: input
			};
		}
	},
	phase: 1
});
//#endregion
export { metadataFileSource };
