import { formatLocale } from "../chokidar/dist/esm/utils/formatter.mjs";
import { getUnmergedDictionaries } from "../unmerged-dictionaries-entry/dist/esm/index.mjs";
import { getIntlayerAPIProxy } from "../api/dist/esm/proxy.mjs";
import { chunkJSON, reconstructFromSingleChunk } from "../chokidar/dist/esm/utils/chunkJSON.mjs";
import { reduceObjectFormat } from "../chokidar/dist/esm/utils/reduceObjectFormat.mjs";
import { verifyIdenticObjectFormat } from "../chokidar/dist/esm/utils/verifyIdenticObjectFormat.mjs";
import { getFilterMissingTranslationsDictionary } from "../core/dist/esm/deepTransformPlugins/getFilterMissingTranslationsContent.mjs";
import { getPerLocaleDictionary } from "../core/dist/esm/deepTransformPlugins/getLocalizedContent.mjs";
import { insertContentInDictionary } from "../core/dist/esm/deepTransformPlugins/insertContentInDictionary.mjs";
import { mergeDictionaries } from "../core/dist/esm/dictionaryManipulator/mergeDictionaries.mjs";
import { basename } from "node:path";
import { ANSIColors, colon, colorize, colorizeNumber, colorizePath, getAppLogger, retryManager } from "@intlayer/config";

//#region ../@intlayer/cli/dist/esm/fill/translateDictionary.mjs
const hasMissingMetadata = (dictionary) => !dictionary.description || !dictionary.title || !dictionary.tags;
const CHUNK_SIZE = 7e3;
const GLOBAL_MAX_RETRY = 2;
const MAX_RETRY = 3;
const RETRY_DELAY = 1e3 * 10;
const translateDictionary = async (task, configuration, options) => {
	const appLogger = getAppLogger(configuration);
	const intlayerAPI = getIntlayerAPIProxy(void 0, configuration);
	const { mode, aiOptions, fillMetadata } = {
		mode: "complete",
		fillMetadata: true,
		...options
	};
	return await retryManager(async () => {
		const baseUnmergedDictionary = getUnmergedDictionaries(configuration)[task.dictionaryKey].find((dict) => dict.localId === task.dictionaryLocalId);
		if (!baseUnmergedDictionary) {
			appLogger(`${task.dictionaryPreset}Dictionary not found in unmergedDictionariesRecord. Skipping.`, { level: "warn" });
			return {
				...task,
				dictionaryOutput: null
			};
		}
		let metadata;
		if (fillMetadata && (hasMissingMetadata(baseUnmergedDictionary) || mode === "review")) {
			const defaultLocaleDictionary = getPerLocaleDictionary(baseUnmergedDictionary, configuration.internationalization.defaultLocale);
			appLogger(`${task.dictionaryPreset} Filling missing metadata for ${colorizePath(basename(baseUnmergedDictionary.filePath))}`, { level: "info" });
			const runAudit = async () => await intlayerAPI.ai.auditContentDeclarationMetadata({
				fileContent: JSON.stringify(defaultLocaleDictionary),
				aiOptions
			});
			metadata = (options?.onHandle ? await options.onHandle(runAudit) : await runAudit()).data?.fileContent;
		}
		let dictionaryToProcess = baseUnmergedDictionary;
		const translatedContent = {};
		for await (const targetLocale of task.targetLocales) {
			/**
			* In complete mode, for large dictionaries, we want to filter all content that is already translated
			*
			* targetLocale: fr
			*
			* { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}
			* { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }
			*
			*/
			if (mode === "complete") dictionaryToProcess = getFilterMissingTranslationsDictionary(dictionaryToProcess, targetLocale);
			dictionaryToProcess = getPerLocaleDictionary(dictionaryToProcess, task.sourceLocale);
			const targetLocaleDictionary = getPerLocaleDictionary(baseUnmergedDictionary, targetLocale);
			const localePreset = colon([
				colorize("[", ANSIColors.GREY_DARK),
				formatLocale(targetLocale),
				colorize("]", ANSIColors.GREY_DARK)
			].join(""), { colSize: 10 });
			const createChunkPreset = (chunkIndex, totalChunks) => {
				if (totalChunks <= 1) return "";
				return colon([
					colorize("[", ANSIColors.GREY_DARK),
					colorizeNumber(chunkIndex + 1),
					colorize(`/${totalChunks}`, ANSIColors.GREY_DARK),
					colorize("]", ANSIColors.GREY_DARK)
				].join(""), { colSize: 5 });
			};
			appLogger(`${task.dictionaryPreset}${localePreset} Preparing ${colorizePath(basename(targetLocaleDictionary.filePath))}`, { level: "info" });
			const chunkedJsonContent = chunkJSON(dictionaryToProcess.content, CHUNK_SIZE);
			const nbOfChunks = chunkedJsonContent.length;
			if (nbOfChunks > 1) appLogger(`${task.dictionaryPreset}${localePreset} Split into ${colorizeNumber(nbOfChunks)} chunks for translation`, { level: "info" });
			const chunkResult = [];
			const chunkPromises = chunkedJsonContent.map((chunk) => {
				const chunkPreset = createChunkPreset(chunk.index, chunk.total);
				if (nbOfChunks > 1) appLogger(`${task.dictionaryPreset}${localePreset}${chunkPreset} Translating chunk`, { level: "info" });
				const chunkContent = reconstructFromSingleChunk(chunk);
				const presetOutputContent = reduceObjectFormat(targetLocaleDictionary.content, chunkContent);
				const executeTranslation = async () => {
					return await retryManager(async () => {
						const translationResult = await intlayerAPI.ai.translateJSON({
							entryFileContent: chunkContent,
							presetOutputContent,
							dictionaryDescription: dictionaryToProcess.description ?? metadata?.description ?? "",
							entryLocale: task.sourceLocale,
							outputLocale: targetLocale,
							mode,
							aiOptions
						});
						if (!translationResult.data?.fileContent) throw new Error("No content result");
						const { isIdentic } = verifyIdenticObjectFormat(translationResult.data.fileContent, chunkContent);
						if (!isIdentic) throw new Error("Translation result does not match expected format");
						return translationResult.data.fileContent;
					}, {
						maxRetry: MAX_RETRY,
						delay: RETRY_DELAY,
						onError: ({ error, attempt, maxRetry }) => {
							const chunkPreset$1 = createChunkPreset(chunk.index, chunk.total);
							appLogger(`${task.dictionaryPreset}${localePreset}${chunkPreset$1} ${colorize("Error filling:", ANSIColors.RED)} ${colorize(error, ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`, { level: "error" });
						}
					})();
				};
				return (options?.onHandle ? options.onHandle(executeTranslation) : executeTranslation()).then((result) => ({
					chunk,
					result
				}));
			});
			(await Promise.all(chunkPromises)).sort((a, b) => a.chunk.index - b.chunk.index).forEach(({ result }) => {
				chunkResult.push(result);
			});
			translatedContent[targetLocale] = mergeDictionaries(chunkResult.map((chunk) => ({
				...dictionaryToProcess,
				content: chunk
			}))).content;
		}
		let dictionaryOutput = {
			...baseUnmergedDictionary,
			...metadata
		};
		for (const targetLocale of task.targetLocales) if (translatedContent[targetLocale]) dictionaryOutput = insertContentInDictionary(dictionaryOutput, translatedContent[targetLocale], targetLocale);
		appLogger(`${task.dictionaryPreset} ${colorize("Translation completed successfully", ANSIColors.GREEN)} for ${colorizePath(basename(dictionaryOutput.filePath))}`, { level: "info" });
		return {
			...task,
			dictionaryOutput
		};
	}, {
		maxRetry: GLOBAL_MAX_RETRY,
		delay: RETRY_DELAY,
		onError: ({ error, attempt, maxRetry }) => {
			appLogger(`${task.dictionaryPreset} ${colorize("Error fill command:", ANSIColors.RED)} ${colorize(error, ANSIColors.GREY_DARK)} - Attempt ${colorizeNumber(attempt + 1)} of ${colorizeNumber(maxRetry)}`, { level: "error" });
		},
		onMaxTryReached: ({ error }) => {
			appLogger(`${task.dictionaryPreset} ${colorize("Maximum number of retries reached:", ANSIColors.RED)} ${colorize(error, ANSIColors.GREY_DARK)}`, { level: "error" });
		}
	})();
};

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