import { backendTranslationSnapshot, } from './backend-translation-snapshot.js';
function isPlainObject(value) {
    return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
}
function parseLocaleData(value) {
    if (typeof value === 'string') {
        return parseLocaleData(JSON.parse(value));
    }
    if (isPlainObject(value)) {
        return value;
    }
    return {};
}
function syncTranslationValue(existing, baseline) {
    if (Array.isArray(baseline)) {
        if (!Array.isArray(existing)) {
            return baseline;
        }
        return baseline.map((item, index) => syncTranslationValue(existing[index], item));
    }
    if (isPlainObject(baseline)) {
        const existingObject = isPlainObject(existing) ? existing : {};
        return Object.fromEntries(Object.entries(baseline).map(([key, value]) => [
            key,
            syncTranslationValue(existingObject[key], value),
        ]));
    }
    if (existing === undefined || existing === null) {
        return baseline;
    }
    return typeof existing === typeof baseline ? existing : baseline;
}
function contentJsonString(content) {
    return JSON.stringify(content);
}
const mergeLocale = (...parts) => parts.reduce((acc, part) => ({ ...acc, ...part }), {});
export class TranslationService {
    constructor(kysely) {
        this.kysely = kysely;
        this.locales = {};
        this.loaded = false;
    }
    async ensureSnapshotSynced() {
        const existingRows = await this.kysely
            .selectFrom('backendTranslation')
            .select(['locale', 'namespace', 'contentJson'])
            .execute();
        const existingMap = new Map(existingRows.map((row) => [`${row.locale}:${row.namespace}`, row]));
        const snapshotMap = new Map(backendTranslationSnapshot.map((row) => [
            `${row.locale}:${row.namespace}`,
            row,
        ]));
        for (const snapshotRow of backendTranslationSnapshot) {
            const key = `${snapshotRow.locale}:${snapshotRow.namespace}`;
            const existingRow = existingMap.get(key);
            if (!existingRow) {
                await this.kysely
                    .insertInto('backendTranslation')
                    .values({
                    locale: snapshotRow.locale,
                    namespace: snapshotRow.namespace,
                    contentJson: contentJsonString(snapshotRow.content),
                })
                    .execute();
                continue;
            }
            const currentContent = parseLocaleData(existingRow.contentJson);
            const syncedContent = syncTranslationValue(currentContent, snapshotRow.content);
            if (contentJsonString(currentContent) === contentJsonString(syncedContent)) {
                continue;
            }
            await this.kysely
                .updateTable('backendTranslation')
                .set({
                contentJson: contentJsonString(syncedContent),
                updatedAt: new Date(),
            })
                .where('locale', '=', snapshotRow.locale)
                .where('namespace', '=', snapshotRow.namespace)
                .execute();
        }
        for (const existingRow of existingRows) {
            const key = `${existingRow.locale}:${existingRow.namespace}`;
            if (snapshotMap.has(key))
                continue;
            await this.kysely
                .deleteFrom('backendTranslation')
                .where('locale', '=', existingRow.locale)
                .where('namespace', '=', existingRow.namespace)
                .execute();
        }
    }
    async init() {
        if (this.loaded)
            return;
        await this.ensureSnapshotSynced();
        const rows = await this.kysely
            .selectFrom('backendTranslation')
            .select(['locale', 'contentJson'])
            .orderBy('locale')
            .orderBy('namespace')
            .execute();
        const locales = {};
        for (const row of rows) {
            locales[row.locale] = mergeLocale(locales[row.locale] ?? {}, parseLocaleData(row.contentJson));
        }
        this.locales = locales;
        this.loaded = true;
    }
    get(locale) {
        if (!this.loaded) {
            throw new Error('TranslationService not loaded. Call init() first.');
        }
        if (!this.locales[locale]) {
            console.warn(`Missing locale: ${locale}`);
        }
        return this.locales[locale] || this.locales.en || {};
    }
    getAll() {
        if (!this.loaded) {
            throw new Error('TranslationService not loaded. Call init() first.');
        }
        return this.locales;
    }
    t(path, locale, variables = {}) {
        const localeData = this.get(locale);
        const keys = path.split('.');
        let value = localeData;
        for (const key of keys) {
            if (value && typeof value === 'object' && key in value) {
                value = value[key];
            }
            else {
                return `[Missing: ${path}]`;
            }
        }
        if (typeof value !== 'string') {
            return `[Invalid: ${path}]`;
        }
        return value.replace(/\{\{(\w+)\}\}|\{(\w+)\}/g, (_, keyA, keyB) => {
            const key = keyA ?? keyB;
            return variables[key] || `{${key}}`;
        });
    }
    tArray(path, locale = 'en') {
        const localeData = this.get(locale);
        const keys = path.split('.');
        let value = localeData;
        for (const key of keys) {
            if (value && typeof value === 'object' && key in value) {
                value = value[key];
            }
            else {
                return [`[Missing: ${path}]`];
            }
        }
        if (!Array.isArray(value)) {
            return [`[Invalid array: ${path}]`];
        }
        return value;
    }
}
//# sourceMappingURL=translation-service.js.map