import { parallelize } from "./chokidar/dist/esm/utils/parallelize.mjs";
import { writeContentDeclaration } from "./chokidar/dist/esm/writeContentDeclaration/writeContentDeclaration.mjs";
import { getIntlayerAPIProxy } from "./api/dist/esm/proxy.mjs";
import { checkCMSAuth } from "./utils/checkAccess.mjs";
import { PullLogger } from "./push/pullLog.mjs";
import { join } from "node:path";
import { existsSync } from "node:fs";
import { ANSIColors, getAppLogger, getConfiguration, getProjectRequire } from "@intlayer/config";

//#region ../@intlayer/cli/dist/esm/pull.mjs
/**
* Fetch distant dictionaries and write them locally,
* with progress indicators and concurrency control.
*/
const pull = async (options) => {
	const appLogger = getAppLogger(options?.configOptions?.override);
	try {
		const config = getConfiguration(options?.configOptions);
		if (!await checkCMSAuth(config)) return;
		const intlayerAPI = getIntlayerAPIProxy(void 0, config);
		const getDictionariesUpdateTimestampResult = await intlayerAPI.dictionary.getDictionariesUpdateTimestamp();
		if (!getDictionariesUpdateTimestampResult.data) throw new Error("No distant dictionaries found");
		let distantDictionariesUpdateTimeStamp = getDictionariesUpdateTimestampResult.data;
		if (options?.dictionaries) distantDictionariesUpdateTimeStamp = Object.fromEntries(Object.entries(distantDictionariesUpdateTimeStamp).filter(([key]) => options.dictionaries?.includes(key)));
		const remoteDictionariesPath = join(config.content.mainDir, "remote_dictionaries.cjs");
		const requireFunction = config.build?.require ?? getProjectRequire();
		const remoteDictionariesRecord = existsSync(remoteDictionariesPath) ? requireFunction(remoteDictionariesPath) : {};
		const entries = Object.entries(distantDictionariesUpdateTimeStamp);
		const keysToFetch = entries.filter(([key, remoteUpdatedAt]) => {
			if (!remoteUpdatedAt) return true;
			const local = remoteDictionariesRecord[key];
			if (!local) return true;
			const localUpdatedAtRaw = local?.updatedAt;
			const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
			if (typeof localUpdatedAt !== "number") return true;
			return remoteUpdatedAt > localUpdatedAt;
		}).map(([key]) => key);
		const cachedKeys = entries.filter(([key, remoteUpdatedAt]) => {
			const localUpdatedAtRaw = remoteDictionariesRecord[key]?.updatedAt;
			const localUpdatedAt = typeof localUpdatedAtRaw === "number" ? localUpdatedAtRaw : localUpdatedAtRaw ? new Date(localUpdatedAtRaw).getTime() : void 0;
			return typeof localUpdatedAt === "number" && typeof remoteUpdatedAt === "number" && localUpdatedAt >= remoteUpdatedAt;
		}).map(([key]) => key);
		if (entries.length === 0) {
			appLogger("No dictionaries to fetch", { level: "error" });
			return;
		}
		appLogger("Fetching dictionaries:");
		const dictionariesStatuses = [...cachedKeys.map((dictionaryKey) => ({
			dictionaryKey,
			status: "imported"
		})), ...keysToFetch.map((dictionaryKey) => ({
			dictionaryKey,
			status: "pending"
		}))];
		const logger$1 = new PullLogger();
		logger$1.update(dictionariesStatuses.map((s) => ({
			dictionaryKey: s.dictionaryKey,
			status: s.status
		})));
		const successfullyFetchedDictionaries = [];
		const processDictionary = async (statusObj) => {
			const isCached = statusObj.status === "imported" || statusObj.status === "up-to-date";
			if (!isCached) {
				statusObj.status = "fetching";
				logger$1.update([{
					dictionaryKey: statusObj.dictionaryKey,
					status: "fetching"
				}]);
			}
			try {
				let sourceDictionary;
				if (isCached) sourceDictionary = remoteDictionariesRecord[statusObj.dictionaryKey];
				if (!sourceDictionary) sourceDictionary = (await intlayerAPI.dictionary.getDictionary(statusObj.dictionaryKey)).data;
				if (!sourceDictionary) throw new Error(`Dictionary ${statusObj.dictionaryKey} not found on remote`);
				const { status } = await writeContentDeclaration(sourceDictionary, config, options);
				statusObj.status = status;
				logger$1.update([{
					dictionaryKey: statusObj.dictionaryKey,
					status
				}]);
				successfullyFetchedDictionaries.push(sourceDictionary);
			} catch (error) {
				statusObj.status = "error";
				statusObj.error = error;
				statusObj.errorMessage = `Error fetching dictionary ${statusObj.dictionaryKey}: ${error}`;
				logger$1.update([{
					dictionaryKey: statusObj.dictionaryKey,
					status: "error"
				}]);
			}
		};
		await parallelize(dictionariesStatuses, processDictionary, 5);
		logger$1.finish();
		const iconFor = (status) => {
			switch (status) {
				case "fetched":
				case "imported":
				case "updated":
				case "up-to-date":
				case "reimported in JSON":
				case "new content file": return "✔";
				case "error": return "✖";
				default: return "⏲";
			}
		};
		const colorFor = (status) => {
			switch (status) {
				case "fetched":
				case "imported":
				case "updated":
				case "up-to-date": return ANSIColors.GREEN;
				case "reimported in JSON":
				case "new content file": return ANSIColors.YELLOW;
				case "error": return ANSIColors.RED;
				default: return ANSIColors.BLUE;
			}
		};
		for (const s of dictionariesStatuses) {
			const icon = iconFor(s.status);
			const color = colorFor(s.status);
			appLogger(` - ${s.dictionaryKey} ${ANSIColors.GREY}[${color}${icon} ${s.status}${ANSIColors.GREY}]${ANSIColors.RESET}`);
		}
		for (const statusObj of dictionariesStatuses) if (statusObj.errorMessage) appLogger(statusObj.errorMessage, { level: "error" });
	} catch (error) {
		appLogger(error, { level: "error" });
	}
};

//#endregion
export { pull };
//# sourceMappingURL=pull.mjs.map