import { log } from "../log.js";
import { defineSource } from "../source.js";
import { ensureArray } from "../utilities/template-helpers.js";
import { fetchWithRetry } from "../utilities/fetch.js";
import { nodePackageJsonSource } from "./node-package-json.js";
import is from "@sindresorhus/is";
import { z } from "zod";
import packageJson from "package-json";
//#region src/lib/sources/node-npm-registry.ts
const nodeNpmRegistrySource = defineSource({
	async discover(context) {
		if (context.options.offline) {
			log.debug("Skipping Node NPM registry data source since we're in offline mode");
			return [];
		}
		let packages = ensureArray(context.metadata?.nodePackageJson);
		if (packages.length === 0 && !context.completedSources?.has("nodePackageJson")) {
			log.debug(`Missing nodePackageJson in source context metadata for ${context.options.path}, extracting it now...`);
			packages = ensureArray(await nodePackageJsonSource.extract(context));
		}
		return packages.filter((packageJson) => {
			if (packageJson.data.private === true || packageJson.data.publishConfig?.access === "restricted") {
				log.debug(`Skipping NPM registry lookup for "${packageJson.data.name}" in "${context.options.path}" because it is a private package`);
				return false;
			}
			return true;
		}).map((packageJson) => packageJson.data.name);
	},
	key: "nodeNpmRegistry",
	async parse(input) {
		log.debug("Extracting npm metadata...");
		const name = input;
		const [metadata, downloadsWeekly, downloadsMonthly, downloadsYearly, downloadsTotal] = await Promise.all([
			packageJson(name, { fullMetadata: true }).catch(() => void 0),
			fetchDownloads(name, "last-week"),
			fetchDownloads(name, "last-month"),
			fetchDownloads(name, "last-year"),
			fetchDownloads(name, "2005-01-01:3000-01-01")
		]);
		if (!metadata) return;
		const hasTypes = Boolean(metadata.types ?? metadata.typings ?? (is.plainObject(metadata) ? metadata.exports : void 0));
		const distribution = is.plainObject(metadata.dist) ? metadata.dist : void 0;
		const time = is.plainObject(metadata.time) ? metadata.time : void 0;
		return {
			data: {
				deprecated: typeof metadata.deprecated === "string" ? metadata.deprecated : void 0,
				downloadsMonthly,
				downloadsTotal: downloadsTotal || void 0,
				downloadsWeekly,
				downloadsYearly,
				fileCount: typeof distribution?.fileCount === "number" ? distribution.fileCount : void 0,
				hasTypes,
				publishDateLatest: typeof time?.modified === "string" ? time.modified : void 0,
				unpackedSizeBytes: typeof distribution?.unpackedSize === "number" ? distribution.unpackedSize : void 0,
				url: `https://www.npmjs.com/package/${encodeURIComponent(name)}`,
				versionLatest: metadata.version
			},
			source: `https://www.npmjs.com/package/${encodeURIComponent(name)}`
		};
	},
	phase: 2
});
const npmDownloadsSchema = z.object({ downloads: z.number() });
async function fetchDownloads(packageName, period) {
	try {
		const response = await fetchWithRetry(`https://api.npmjs.org/downloads/point/${period}/${encodeURIComponent(packageName)}`);
		if (!response.ok) return void 0;
		return npmDownloadsSchema.parse(await response.json()).downloads;
	} catch {
		return;
	}
}
//#endregion
export { nodeNpmRegistrySource };
