import { extname } from 'node:path';
import { passthrough } from '@yeoman/transform';
import { Minimatch } from 'minimatch';
import { createJhiTransformTranslateReplacer, createJhiTransformTranslateStringifyReplacer, createJhiTranslateReplacer, escapeHtmlTranslationValue, escapeTsTranslationValue, } from '../../languages/support/index.js';
const PLACEHOLDER_REGEX = /(?:placeholder|title)=['|"](\{\{\s?['|"]([a-zA-Z0-9.\-_]+)['|"]\s?\|\s?translate\s?\}\})['|"]/.source;
const JHI_TRANSLATE_REGEX = /(\n?\s*[a-z][a-zA-Z]*Translate="[a-zA-Z0-9 +{}'_!?.]+")/.source;
const TRANSLATE_VALUES_REGEX = /(\n?\s*\[translateValues\]="\{(?:(?!\}").)*?\}")/.source;
const TRANSLATE_REGEX = [JHI_TRANSLATE_REGEX, TRANSLATE_VALUES_REGEX].join('|');
function getTranslationValue(getWebappTranslation, key, data) {
    return getWebappTranslation(key, data) || undefined;
}
function replaceTranslationKeysWithText(getWebappTranslation, content, regexSource, { keyIndex = 1, replacementIndex = 1, escape, } = {}) {
    const regex = new RegExp(regexSource, 'g');
    const allMatches = content.matchAll(regex);
    for (const match of allMatches) {
        const key = match[keyIndex];
        const target = match[replacementIndex];
        let translation = getTranslationValue(getWebappTranslation, key);
        if (escape) {
            translation = escape(translation, match);
        }
        content = content.replace(target, translation);
    }
    return content;
}
function replaceJSTranslation(getWebappTranslation, content, jsKey) {
    return replaceTranslationKeysWithText(getWebappTranslation, content, `${jsKey}\\s?:\\s?['|"]([a-zA-Z0-9.\\-_]+\\.[a-zA-Z0-9.\\-_]+)['|"]`, {
        escape: (translation, match) => translation.replaceAll(match[0].slice(-1), `\\${match[0].slice(-1)}`),
    });
}
function replacePageTitles(getWebappTranslation, content) {
    return replaceJSTranslation(getWebappTranslation, content, 'title');
}
function replacePlaceholders(getWebappTranslation, content) {
    return replaceTranslationKeysWithText(getWebappTranslation, content, PLACEHOLDER_REGEX, { keyIndex: 2 });
}
function replaceErrorMessage(getWebappTranslation, content) {
    return replaceJSTranslation(getWebappTranslation, content, 'errorMessage');
}
const tagTranslation = (getWebappTranslation, { enableTranslation, jhiPrefix }, { key, parsedInterpolate, prefix, suffix }) => {
    const translatedValueInterpolate = parsedInterpolate
        ? Object.fromEntries(Object.entries(parsedInterpolate).map(([key, value]) => [key, `{{ ${value} }}`]))
        : undefined;
    const translatedValue = escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key, translatedValueInterpolate));
    if (enableTranslation) {
        const translateValuesAttr = parsedInterpolate
            ? ` [translateValues]="{ ${Object.entries(parsedInterpolate)
                .map(([key, value]) => `${key}: ${value}`)
                .join(', ')} }"`
            : '';
        return ` ${jhiPrefix}Translate="${key}"${translateValuesAttr}${prefix}${translatedValue}${suffix}`;
    }
    return `${prefix}${translatedValue}${suffix}`;
};
const validationTagTranslation = (getWebappTranslation, { enableTranslation, jhiPrefix }, { key, parsedInterpolate, prefix, suffix }) => {
    if (!parsedInterpolate || Object.keys(parsedInterpolate).length === 0) {
        throw new Error(`No interpolation values found for translation key ${key}, use __jhiTranslateTag__ instead.`);
    }
    const translatedValue = escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key, parsedInterpolate));
    if (enableTranslation) {
        const translateValuesAttr = parsedInterpolate
            ? ` [translateValues]="{ ${Object.entries(parsedInterpolate)
                .map(([key, value]) => `${key}: '${value}'`)
                .join(', ')} }"`
            : '';
        return ` ${jhiPrefix}Translate="${key}"${translateValuesAttr}${prefix}${translatedValue}${suffix}`;
    }
    return `${prefix}${translatedValue}${suffix}`;
};
const tagPipeTranslation = (getWebappTranslation, { enableTranslation, jhiPrefix }, { key, parsedInterpolate, prefix, suffix }) => {
    if (!parsedInterpolate || Object.keys(parsedInterpolate).length === 0) {
        throw new Error(`No interpolation values found for translation key ${key}, use __jhiTranslateTag__ instead.`);
    }
    const translatedValueInterpolate = Object.fromEntries(Object.entries(parsedInterpolate).map(([key, value]) => [key, getWebappTranslation(value)]));
    const translatedValue = escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key, translatedValueInterpolate));
    if (enableTranslation) {
        const translateValuesAttr = ` [translateValues]="{ ${Object.entries(parsedInterpolate)
            .map(([key, value]) => `${key}: ('${value}' | translate)`)
            .join(', ')} }"`;
        return ` ${jhiPrefix}Translate="${key}"${translateValuesAttr}${prefix}${translatedValue}${suffix}`;
    }
    return `${prefix}${translatedValue}${suffix}`;
};
const tagEnumTranslation = (getWebappTranslation, { enableTranslation, jhiPrefix }, { key, parsedInterpolate, prefix, suffix }) => {
    if (!parsedInterpolate?.value) {
        throw new Error(`Value is required for TagEnum ${key}.`);
    }
    const { value, fallback } = parsedInterpolate;
    const translatedValue = `{{ ${JSON.stringify(getTranslationValue(getWebappTranslation, key))}[${value}]${fallback ? ` || ${fallback}` : ''} }}`;
    if (enableTranslation) {
        return ` [${jhiPrefix}Translate]="'${key}.' + (${parsedInterpolate?.value})"${prefix}${translatedValue}${suffix}`;
    }
    return `${prefix}${translatedValue}${suffix}`;
};
const pipeTranslation = (getWebappTranslation, { enableTranslation }, { key, prefix, suffix }) => {
    if (enableTranslation) {
        return `${prefix}{{ '${key}' | translate }}${suffix}`;
    }
    return `${prefix}${escapeHtmlTranslationValue(getTranslationValue(getWebappTranslation, key))}${suffix}`;
};
const valueTranslation = (getWebappTranslation, _replacerOptions, { filePath, key, prefix, suffix }) => {
    let translationValue = getTranslationValue(getWebappTranslation, key);
    const fileExtension = extname(filePath);
    if (fileExtension === '.html') {
        translationValue = escapeHtmlTranslationValue(translationValue);
    }
    else if (fileExtension === '.ts') {
        translationValue = escapeTsTranslationValue(translationValue);
    }
    return `${prefix}${translationValue}${suffix}`;
};
const pipeEnumTranslation = (getWebappTranslation, { enableTranslation }, { key, parsedInterpolate, prefix, suffix }) => {
    if (!parsedInterpolate?.value) {
        throw new Error(`Value is required for TagEnum ${key}.`);
    }
    const { value, fallback } = parsedInterpolate;
    if (enableTranslation) {
        return `${prefix}{{ '${key}.' + ${value} | translate }}${suffix}`;
    }
    const translatedValue = `{{ ${JSON.stringify(getTranslationValue(getWebappTranslation, key))}[${value}]${fallback ? ` ?? ${fallback}` : ''} }}`;
    return `${prefix}${translatedValue}${suffix}`;
};
const replaceImplementations = {
    Tag: tagTranslation,
    TagPipe: tagPipeTranslation,
    TagEnum: tagEnumTranslation,
    ValidationTag: validationTagTranslation,
    Pipe: pipeTranslation,
    PipeEnum: pipeEnumTranslation,
    Value: valueTranslation,
};
export const createTranslationReplacer = (getWebappTranslation, opts) => {
    const htmlJhiTranslateReplacer = createJhiTransformTranslateReplacer(getWebappTranslation, { escapeHtml: true });
    const htmlJhiTranslateStringifyReplacer = createJhiTransformTranslateStringifyReplacer(getWebappTranslation);
    let translationReplacer;
    const enableTranslation = typeof opts === 'boolean' ? opts : opts.enableTranslation;
    if (typeof opts !== 'boolean') {
        translationReplacer = createJhiTranslateReplacer(optsReplacer => {
            const replacer = replaceImplementations[optsReplacer.type] ??
                (() => {
                    throw new Error(`Translation type not supported ${optsReplacer.type}`);
                });
            return replacer(getWebappTranslation, opts, optsReplacer);
        }, { prefixPattern: '>\\s*', suffixPattern: '\\s*<' });
    }
    return function replaceAngularTranslations(content, filePath) {
        if (/\.html$/.test(filePath)) {
            if (!enableTranslation) {
                content = content.replace(new RegExp(TRANSLATE_REGEX, 'g'), '');
                content = replacePlaceholders(getWebappTranslation, content);
            }
        }
        if (/(:?\.html|component\.ts)$/.test(filePath)) {
            content = htmlJhiTranslateReplacer(content);
            content = htmlJhiTranslateStringifyReplacer(content);
        }
        if (/(:?\.html|.ts)$/.test(filePath)) {
            content = translationReplacer?.(content, filePath);
        }
        if (!enableTranslation) {
            if (/(:?route|module)\.ts$/.test(filePath)) {
                content = replacePageTitles(getWebappTranslation, content);
            }
            if (/error\.route\.ts$/.test(filePath)) {
                content = replaceErrorMessage(getWebappTranslation, content);
            }
        }
        return content;
    };
};
const minimatch = new Minimatch('**/*{.html,.ts}');
export const isTranslatedAngularFile = file => minimatch.match(file.path);
export const translateAngularFilesTransform = (getWebappTranslation, opts) => {
    const translate = createTranslationReplacer(getWebappTranslation, opts);
    return passthrough(file => {
        file.contents = Buffer.from(translate(file.contents.toString(), file.path));
    });
};
