import { NodeType } from "../types/dist/esm/nodeType.mjs";
import { deepTransformNode } from "../interpreter/getContent/deepTransform.mjs";
import { built_default } from "../config/dist/esm/built.mjs";
import { getTranslation } from "../interpreter/getTranslation.mjs";
import { translation } from "../transpiler/translation/translation.mjs";

//#region ../@intlayer/cli/dist/esm/core/dist/esm/deepTransformPlugins/getFilterMissingTranslationsContent.mjs
/**
* Helper function to check if a node or its children contain translation nodes
*/
const hasTranslationNodes = (node) => {
	if (typeof node !== "object" || node === null) return false;
	if (node?.nodeType === NodeType.Translation) return true;
	if (Array.isArray(node)) return node.some(hasTranslationNodes);
	return Object.values(node).some(hasTranslationNodes);
};
/**
* Get all keys from an object, recursively
*/
const getObjectKeys = (obj) => {
	const keys = /* @__PURE__ */ new Set();
	if (typeof obj !== "object" || obj === null) return keys;
	for (const key in obj) keys.add(key);
	return keys;
};
/**
* Check if two objects have the same structure (same keys)
*/
const hasSameStructure = (obj1, obj2) => {
	if (typeof obj1 !== "object" || typeof obj2 !== "object") return typeof obj1 === typeof obj2;
	if (obj1 === null || obj2 === null) return obj1 === obj2;
	if (Array.isArray(obj1) !== Array.isArray(obj2)) return false;
	const keys1 = getObjectKeys(obj1);
	const keys2 = getObjectKeys(obj2);
	if (keys1.size !== keys2.size) return false;
	for (const key of keys1) if (!keys2.has(key)) return false;
	return true;
};
/**
* Check if all locales in a translation node have the same structure (recursively)
* Returns an object with locales that have missing keys
*/
const checkTranslationStructureConsistency = (translationNode) => {
	const locales = Object.keys(translationNode);
	const localesWithMissingKeys = /* @__PURE__ */ new Set();
	if (locales.length <= 1) return {
		hasInconsistency: false,
		localesWithMissingKeys
	};
	const checkStructureRecursive = (path, localeValues) => {
		const localesWithIssues = /* @__PURE__ */ new Set();
		const allKeys = /* @__PURE__ */ new Set();
		const objectLocales = /* @__PURE__ */ new Map();
		for (const [locale, value] of localeValues.entries()) if (typeof value === "object" && value !== null && !Array.isArray(value)) {
			objectLocales.set(locale, value);
			const keys = getObjectKeys(value);
			for (const key of keys) allKeys.add(key);
		}
		if (objectLocales.size === 0) return localesWithIssues;
		for (const [locale, value] of objectLocales.entries()) if (getObjectKeys(value).size !== allKeys.size) localesWithIssues.add(locale);
		for (const key of allKeys) {
			const nestedValues = /* @__PURE__ */ new Map();
			for (const [locale, value] of objectLocales.entries()) if (value[key] !== void 0) nestedValues.set(locale, value[key]);
			if (nestedValues.size > 1) {
				const nestedIssues = checkStructureRecursive(path ? `${path}.${key}` : key, nestedValues);
				for (const locale of nestedIssues) localesWithIssues.add(locale);
			}
		}
		return localesWithIssues;
	};
	const rootValues = /* @__PURE__ */ new Map();
	for (const locale of locales) rootValues.set(locale, translationNode[locale]);
	const issuesFound = checkStructureRecursive("", rootValues);
	const hasInconsistency = issuesFound.size > 0;
	for (const locale of issuesFound) localesWithMissingKeys.add(locale);
	return {
		hasInconsistency,
		localesWithMissingKeys
	};
};
/**
* Check if array elements have consistent structures
*/
const checkArrayStructureConsistency = (arr) => {
	if (arr.length <= 1) return true;
	const firstElement = arr[0];
	for (let i = 1; i < arr.length; i++) if (!hasSameStructure(firstElement, arr[i])) return false;
	return true;
};
/** Translation plugin. Replaces node with a locale string if nodeType = Translation. */
const filterMissingTranslationsOnlyPlugin = (localeToCheck) => ({
	id: "filter-missing-translations-only-plugin",
	canHandle: (node) => {
		return typeof node === "object" && node !== null;
	},
	transform: (node, props, deepTransformNode$1) => {
		if (typeof node === "object" && node?.nodeType === NodeType.Translation) {
			const result = structuredClone(node[NodeType.Translation]);
			const hasLocaleTranslation = Object.keys(result).includes(localeToCheck);
			const { hasInconsistency, localesWithMissingKeys } = checkTranslationStructureConsistency(result);
			const hasStructuralIssue = hasInconsistency && localesWithMissingKeys.has(localeToCheck);
			if (hasLocaleTranslation && !hasStructuralIssue) return;
			for (const key in result) {
				const childProps = {
					...props,
					children: result[key],
					keyPath: [...props.keyPath, {
						type: NodeType.Translation,
						key
					}]
				};
				result[key] = deepTransformNode$1(result[key], {
					...childProps,
					plugins: [...(props.plugins ?? []).filter((plugin) => plugin.id !== "filter-missing-translations-only-plugin")]
				});
			}
			const baseLocale = built_default?.internationalization?.defaultLocale;
			const availableLocales = Object.keys(result);
			if (availableLocales.length === 0) return;
			const fallbackLocale = availableLocales.includes(baseLocale) ? baseLocale : availableLocales[0];
			const fallbackValue = getTranslation(result, baseLocale, fallbackLocale);
			return translation({ [fallbackLocale]: fallbackValue });
		} else if (typeof node === "object" && node !== null && !Array.isArray(node) && !node?.nodeType) {
			const result = {};
			let hasMissingTranslations = false;
			const arrayKeysIncluded = [];
			const primitiveSiblingsToAppend = [];
			for (const key in node) {
				const originalChild = node[key];
				const transformedChild = deepTransformNode$1(originalChild, {
					...props,
					children: originalChild,
					keyPath: [...props.keyPath, {
						type: NodeType.Object,
						key
					}]
				});
				if (originalChild === null || typeof originalChild !== "object" && typeof originalChild !== "function") {
					if (originalChild !== void 0) primitiveSiblingsToAppend.push(originalChild);
					continue;
				}
				if (transformedChild !== void 0 && (hasTranslationNodes(originalChild) || Array.isArray(originalChild))) {
					result[key] = transformedChild;
					hasMissingTranslations = true;
					if (Array.isArray(transformedChild)) arrayKeysIncluded.push(key);
				}
			}
			if (arrayKeysIncluded.length > 0 && primitiveSiblingsToAppend.length > 0) {
				const targetArrayKey = arrayKeysIncluded[0];
				if (Array.isArray(result[targetArrayKey])) {
					result[targetArrayKey] = [...result[targetArrayKey], ...primitiveSiblingsToAppend];
					hasMissingTranslations = true;
				}
			}
			return hasMissingTranslations ? result : void 0;
		} else if (Array.isArray(node)) {
			const hasConsistentStructure = checkArrayStructureConsistency(node);
			const result = node.map((child, index) => {
				return deepTransformNode$1(child, {
					...props,
					children: child,
					keyPath: [...props.keyPath, {
						type: NodeType.Array,
						key: index
					}]
				});
			}).filter((item) => item !== null && item !== void 0);
			if (!hasConsistentStructure && result.length === 0) return node;
			return result.length > 0 ? result : void 0;
		}
		return node;
	}
});
/**
* For each translation node, it compare is both localeToCheck and baseLocale are present.
*
* If yes, it should remove the node from the content.
* If no, it should keep the node
*
* In complete mode, for large dictionaries, we want to filter all content that is already translated
*
* locale: fr
*
* { test1: t({ ar: 'Hello', en: 'Hello', fr: 'Bonjour' } }) -> {}
* { test2: t({ ar: 'Hello', en: 'Hello' }) } -> { test2: t({ ar: 'Hello', en: 'Hello' }) }
*
*/
const getFilterMissingTranslationsContent = (node, localeToCheck, nodeProps) => {
	const plugins = [filterMissingTranslationsOnlyPlugin(localeToCheck), ...nodeProps.plugins ?? []];
	const result = deepTransformNode(node, {
		...nodeProps,
		plugins
	});
	if (result === void 0) return {};
	return JSON.parse(JSON.stringify(result));
};
const getFilterMissingTranslationsDictionary = (dictionary, localeToCheck) => ({
	...dictionary,
	content: getFilterMissingTranslationsContent(dictionary.content, localeToCheck, {
		dictionaryKey: dictionary.key,
		keyPath: [],
		plugins: []
	})
});

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