import { render, waitFor } from '@testing-library/react';
import React, { useEffect } from 'react';

import { I18n, I18nProvider, useI18n } from './../src/index';

test('Should render key', () => {
    function Root() {
        return (
            <I18nProvider lngDict={{ hello: 'Hello, world!' }} locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        return <p>{i18n.t('hello')}</p>;
    }

    const { getByText } = render(<Root />);
    expect(getByText('Hello, world!')).toBeInTheDocument();
});

test('Should interpolate key', () => {
    function Root() {
        return (
            <I18nProvider lngDict={{ welcome: 'Welcome, {{username}}!' }} locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        return <p>{i18n.t('welcome', { username: 'Bernd' })}</p>;
    }

    const { getByText } = render(<Root />);
    expect(getByText('Welcome, Bernd!')).toBeInTheDocument();
});

test('Should print current locale', () => {
    function Root() {
        return (
            <I18nProvider lngDict={{ hello: 'Hello, world!' }} locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        return <p>{i18n.locale()}</p>;
    }

    const { getByText } = render(<Root />);
    expect(getByText('en')).toBeInTheDocument();
});

test('Should pluralize', () => {
    function Root() {
        return (
            <I18nProvider
                lngDict={{
                    warning: 'WARNING: {{birds}}, {{foo}}',
                    birds: {
                        other: 'birds',
                        one: 'bird',
                        two: 'two birds',
                        few: 'some birds'
                    }
                }}
                locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        const t = i18n.withPlural();
        return <p>{t('warning', { birds: 2, foo: 'bar' })}</p>;
    }

    const { getByText } = render(<Root />);
    expect(getByText('WARNING: two birds, bar')).toBeInTheDocument();
});

test('Should fallback to default behaviour when no number is passed', () => {
    function Root() {
        return (
            <I18nProvider
                lngDict={{
                    warning: 'WARNING: {{birds}}',
                    birds: {
                        other: 'birds',
                        one: 'bird',
                        two: 'two birds',
                        few: 'some birds'
                    }
                }}
                locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        const t = i18n.withPlural();
        return <p>{t('warning', { birds: 'no-number' })}</p>;
    }

    const { getByText } = render(<Root />);
    expect(getByText('WARNING: no-number')).toBeInTheDocument();
});

test('Should be able to pass a custom i18n instance', () => {
    const i18nInstance = I18n({
        en: { hello: 'Hello, world!' }
    });
    function Root() {
        return (
            <I18nProvider i18nInstance={i18nInstance} locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        return <p>{i18n.t('hello')}</p>;
    }

    const { getByText } = render(<Root />);
    expect(getByText('Hello, world!')).toBeInTheDocument();
});

test('Should be able to pass a custom i18n instance and langDict', () => {
    const i18nInstance = I18n();
    function Root() {
        return (
            <I18nProvider
                i18nInstance={i18nInstance}
                locale="en"
                lngDict={{ hello: 'Hello, world!' }}>
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();
        return <p>{i18n.t('hello')}</p>;
    }

    const { getByText } = render(<Root />);
    expect(i18nInstance.table('en')).toEqual({ hello: 'Hello, world!' });
    expect(getByText('Hello, world!')).toBeInTheDocument();
});

test('Should be able to change locale', async () => {
    const i18nInstance = I18n({
        en: { hello: 'Hello, world!' }
    });
    function Root() {
        return (
            <I18nProvider i18nInstance={i18nInstance} locale={i18nInstance.locale()}>
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();

        useEffect(() => {
            i18n.set('de', { hello: 'Hello, Welt!' });
            i18n.locale('de');
            // eslint-disable-next-line react-hooks/exhaustive-deps
        }, []);

        return <p>{i18n.t('hello')}</p>;
    }

    const { getByText } = render(<Root />);

    await waitFor(() => {
        expect(i18nInstance.locale()).toEqual('de');
        expect(i18nInstance.table('en')).toEqual({ hello: 'Hello, world!' });
        expect(i18nInstance.table('de')).toEqual({ hello: 'Hello, Welt!' });
        expect(getByText('Hello, Welt!')).toBeInTheDocument();
    });
});

test('Should be able to set new keys without changing locale', () => {
    const i18nInstance = I18n({
        en: { hello: 'Hello, world!' }
    });
    function Root() {
        return (
            <I18nProvider i18nInstance={i18nInstance} locale="en">
                <Child />
            </I18nProvider>
        );
    }
    function Child() {
        const i18n = useI18n();

        useEffect(() => {
            i18n.set('de', { hello: 'Hello, Welt!' });
            // eslint-disable-next-line react-hooks/exhaustive-deps
        }, []);

        return <p>{i18n.t('hello')}</p>;
    }

    const { getByText } = render(<Root />);
    expect(i18nInstance.table('de')).toEqual({ hello: 'Hello, Welt!' });
    expect(getByText('Hello, world!')).toBeInTheDocument();
});