import type { OtherLanguageWrap } from '../src/index.js'
import { Message, PeersIndex } from '@mtcute/core'
import { MessageContext } from '@mtcute/dispatcher'

import { describe, expect, it } from 'vitest'
import { createMtcuteI18n } from '../src/index.js'
import { createPluralEnglish, pluralizeEnglish } from '../src/plurals/english.js'
import { createPluralRussian } from '../src/plurals/russian.js'

describe('i18n', () => {
    const en = {
        direct: 'Hello',
        fn: () => 'World',
        withArgs: (name: string) => `Welcome ${name}`,
        withArgsObj: ({ name }: { name: string }) => `Welcome ${name}`,
        nested: {
            string: 'Hello',
            nested: {
                fn: () => 'Hello',
            },
        },
        plural: createPluralEnglish('a message', n => `${n} messages`),
        plural2: createPluralEnglish('a message', (n: number, s: string) => `${n} messages from ${s}`),
        plural3: (n: number) => `${n} ${pluralizeEnglish(n, 'message', 'messages')}`,
    }
    const ru: OtherLanguageWrap<typeof en> = {
        direct: 'Привет',
        withArgs: (name: string) => `Привет ${name}`,
        nested: {
            nested: {
                fn: 'Привет',
            },
        },
        plural: createPluralRussian(
            n => `${n} сообщение`,
            n => `${n} сообщения`,
            n => `${n === 0 ? 'нет' : n} сообщений`,
        ),
    }

    const tr = createMtcuteI18n({
        primaryLanguage: {
            name: 'en',
            strings: en,
        },
        otherLanguages: { ru },
    })

    it('should work with direct string', () => {
        expect(tr('en', 'direct')).to.equal('Hello')
    })

    it('should work with function without args', () => {
        expect(tr('en', 'fn')).to.equal('World')
    })

    it('should work with function with args', () => {
        expect(tr('en', 'withArgs', '')).to.equal('Welcome ')
        expect(tr('en', 'withArgs', 'John')).to.equal('Welcome John')
        expect(tr('en', 'withArgsObj', { name: 'John' })).to.equal('Welcome John')
    })

    it('should work with nested values', () => {
        expect(tr('en', 'nested.string')).to.equal('Hello')
        expect(tr('en', 'nested.nested.fn')).to.equal('Hello')
    })

    it('should work with other languages', () => {
        expect(tr('ru', 'direct')).to.equal('Привет')
        expect(tr('ru', 'withArgs', 'Ваня')).to.equal('Привет Ваня')
        expect(tr('ru', 'nested.nested.fn')).to.equal('Привет')
    })

    it('should fallback to primary language when string is not translated', () => {
        expect(tr('ru', 'fn')).to.equal('World')
        expect(tr('ru', 'withArgsObj', { name: 'Ваня' })).to.equal('Welcome Ваня')
        expect(tr('ru', 'nested.string')).to.equal('Hello')
    })

    it('should fallback to primary language when language is not available', () => {
        expect(tr('kz', 'direct')).to.equal('Hello')
        expect(tr(null, 'direct')).to.equal('Hello')
    })

    it('should parse language from a message', () => {
        const message = new MessageContext(
            null as never,
            new Message(
                { _: 'message', peerId: { _: 'peerUser', userId: 1 } } as never,
                PeersIndex.from({
                    users: [{ _: 'user', id: 1, firstName: 'Пыня', langCode: 'ru' }],
                }),
            ),
        )

        expect(tr(message, 'direct')).to.equal('Привет')
    })

    it('should accept custom adapters', () => {
        const tr = createMtcuteI18n({
            primaryLanguage: {
                name: 'en',
                strings: en,
            },
            otherLanguages: { ru },
            adapter: (num: number) => (num === 1 ? 'en' : 'ru'),
        })

        expect(tr(1, 'direct')).to.equal('Hello')
        expect(tr(2, 'direct')).to.equal('Привет')
    })

    describe('plurals', () => {
        it('should pluralize correctly in english', () => {
            expect(tr('en', 'plural', 1)).to.equal('a message')
            expect(tr('en', 'plural', 2)).to.equal('2 messages')

            expect(tr('en', 'plural2', 1, 'baka')).to.equal('a message')
            expect(tr('en', 'plural2', 2, 'baka')).to.equal('2 messages from baka')

            expect(tr('en', 'plural3', 1)).to.equal('1 message')
            expect(tr('en', 'plural3', 2)).to.equal('2 messages')
        })

        it('should pluralize correctly in russian', () => {
            expect(tr('ru', 'plural', 0)).to.equal('нет сообщений')
            expect(tr('ru', 'plural', 1)).to.equal('1 сообщение')
            expect(tr('ru', 'plural', 2)).to.equal('2 сообщения')
            expect(tr('ru', 'plural', 5)).to.equal('5 сообщений')
        })
    })
})
