import { describe, it, afterEach, expect, vi } from 'vitest';
import { readFileSync } from 'node:fs';
import { fileURLToPath } from 'node:url';
import { dirname, resolve } from 'node:path';

import { translate } from '../../../static/js/utils/i18nHelpers.js';

const repoRoot = resolve(dirname(fileURLToPath(import.meta.url)), '../../..');

/**
 * Real en.json translations backed by a minimal `window.i18n` stub that mirrors
 * the nested lookup + {param} interpolation of static/js/i18n/index.js, so the
 * assertions exercise actual key resolution rather than key presence.
 */
const loadEnTranslations = () =>
    JSON.parse(readFileSync(resolve(repoRoot, 'locales/en.json'), 'utf8'));

const installWindowI18n = () => {
    const translations = loadEnTranslations();

    const interpolate = (str, params) =>
        str.replace(/\{\{?(\w+)\}?\}/g, (match, key) =>
            params[key] !== undefined ? params[key] : match,
        );

    window.i18n = {
        t: (key, params = {}) => {
            const keys = key.split('.');
            let value = translations;
            for (const k of keys) {
                if (value && typeof value === 'object' && k in value) {
                    value = value[k];
                } else {
                    console.warn(`Translation key not found: ${key}`);
                    return key;
                }
            }
            if (typeof value !== 'string') {
                console.warn(`Translation key is not a string: ${key}`);
                return key;
            }
            return interpolate(value, params);
        },
        getCurrentLocale: () => 'en',
    };
};

afterEach(() => {
    delete window.i18n;
});

describe('translate() with real en.json locale', () => {
    it('resolves undo toast keys with interpolation', () => {
        installWindowI18n();

        expect(translate('toast.undo.deleted', { name: 'x' })).toBe('Deleted x');
        expect(translate('toast.undo.deletedBulk', { count: 3 })).toBe('Deleted 3 item(s)');
        expect(translate('toast.undo.action')).toBe('Undo');
        expect(translate('toast.undo.restored')).toBe('Item restored');
        expect(translate('toast.undo.expired')).toBe(
            'Undo window expired. The item was permanently deleted.',
        );
        expect(translate('toast.undo.failed', { error: 'boom' })).toBe('Undo failed: boom');
    });

    it('resolves delete-model modal keys with interpolation', () => {
        installWindowI18n();

        expect(translate('modals.deleteModel.recoverableWarning')).toBe(
            'This will permanently delete the file after 20 seconds unless you undo.',
        );
        expect(translate('modals.deleteModel.freesSpace', { size: '1.2 MB' })).toBe(
            'Frees 1.2 MB',
        );
    });

    it('returns the raw key when no translation exists (fallback contract)', () => {
        installWindowI18n();
        const warnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});

        expect(translate('toast.undo.nonExistentKey')).toBe('toast.undo.nonExistentKey');

        warnSpy.mockRestore();
    });
});
