import I18n from '../src';
import IntlMessageFormat from 'intl-messageformat';

import zh from './resources/zh';
import en from './resources/en';

const resources = { en, zh } as const;

function getText(key: keyof typeof resources.zh, interpolator?: any) {
  const targetText = resources[I18n.language][key];
  try {
    return new IntlMessageFormat(targetText, I18n.language).format(interpolator || {});
  } catch (err) {
    return targetText;
  }
}

const mockPlugin = { type: 'logger', name: 'mockPlugin' } as const;
const mockThirdPartyPlugin = {
  type: 'intl3rdParty',
  name: 'mockThirdPartyPlugin',
  async init() { }
} as const;
const mockErrorThirdPartyPlugin = {
  type: 'intl3rdParty',
  name: 'mockErrorThirdPartyPlugin',
} as const;
const mockTransformerPlugin: any = {
  type: 'languageTransformer',
  name: 'mockTransformerPlugin',
  process(lng: string) { return lng }
} as const;

function init() {
  return I18n
    .use(mockPlugin)
    .use(mockThirdPartyPlugin)
    .use(mockErrorThirdPartyPlugin)
    .use(mockTransformerPlugin)
    .init({
      keySeparator: false,
      react: { useSuspense: false },
      resources: {
        zh: { translation: resources.zh },
        en: { translation: resources.en }
      },
      lng: 'en',
      fallbackLng: ['zh', 'en']
    });
}

test('I18n 实例未初始化', () => {
  const spy = jest.spyOn(console, 'error');
  expect(I18n.t('SIMPLE_PARAM')).toBe('SIMPLE_PARAM');
  expect(spy).toBeCalledWith(
    'Starling_intl: [ERROR]',
    'The instance has not been initialized: i18n.t(\'SIMPLE_PARAM\');');
})

describe('I18n 基本职能与属性', () => {
  beforeAll(init);

  it('获取当前语言', () => {
    expect(I18n.language).toBe('en');
  });

  it('获取全部语言', () => {
    expect(I18n.getLanguages()).toEqual(['en', 'zh']);
  });

  it('切换语言 - setLang', async () => {
    await new Promise(resolve => I18n.setLang('zh', resolve));

    expect(I18n.language).toBe('zh');
    expect(I18n.getLanguages()).toEqual(['zh', 'en']);
    expect(I18n.t('SIMPLE_TEXT')).toBe(getText('SIMPLE_TEXT'));

    await new Promise(resolve => I18n.setLang('en', resolve));
  });

  it('切换语言 - setLangWithPromise', async () => {
    await I18n.setLangWithPromise('zh');

    expect(I18n.language).toBe('zh');
    expect(I18n.getLanguages()).toEqual(['zh', 'en']);
    expect(I18n.t('SIMPLE_TEXT')).toBe(getText('SIMPLE_TEXT'));

    await I18n.setLangWithPromise('en');
  });

  it('切换语言失败 - setLangWithPromise', async () => {
    // @ts-ignore
    expect(I18n.setLangWithPromise(666)).rejects.toEqual('error');
  });

  it('获取语言文本排版方向', () => {
    expect(I18n.dir('zh')).toBe('ltr');
    expect(I18n.dir('ar')).toBe('rtl');
  });

  it('动态添加文案', () => {
    expect(I18n.t('OVERRIDE_TEXT')).toBe(getText('OVERRIDE_TEXT'));

    I18n.addResourceBundle(I18n.language, 'translation', { OVERRIDE_TEXT: 'hahaha' }, true, true);

    expect(I18n.t('OVERRIDE_TEXT')).toBe('hahaha');
  });

  it('重复 use 一个插件', () => {
    const spy = jest.spyOn(console, 'warn');

    I18n.use(mockPlugin);

    expect(spy).toHaveBeenCalledWith('Starling_intl: [WARNING]', 'Plugin: %s has beeninit installed.', mockPlugin.name);
  });

  it('Key 为空', () => {
    expect(I18n.t('')).toBe('');
  });
});

describe('ICU 语法测试', () => {
  beforeAll(init);

  it('基本语法', () => {
    expect(I18n.t('SIMPLE_TEXT')).toBe(getText('SIMPLE_TEXT'));
  });

  it('简单参数', () => {
    expect(I18n.t('SIMPLE_PARAM', { name: 'starling' })).toBe(getText('SIMPLE_PARAM', { name: 'starling' }));
  });

  it('格式化 number 类型参数', () => {
    expect(I18n.t('NUMBERED_PARAM', { count: 1 })).toBe(getText('NUMBERED_PARAM', { count: 1 }));
    expect(I18n.t('NUMBERED_PARAM', { count: 100 })).toBe(getText('NUMBERED_PARAM', { count: 100 }));
    expect(I18n.t('NUMBERED_PARAM', { count: 10000 })).toBe(getText('NUMBERED_PARAM', { count: 10000 }));
  });

  it('格式化 number, percent 类型参数', () => {
    expect(I18n.t('NUMBERED_PARAM_PERCENT', { per: 0.5 })).toBe(getText('NUMBERED_PARAM_PERCENT', { per: 0.5 }));
    expect(I18n.t('NUMBERED_PARAM_PERCENT', { per: 0 })).toBe(getText('NUMBERED_PARAM_PERCENT', { per: 0 }));
  });

  it('格式化 date 类型的参数 ', () => {
    const now = new Date();
    expect(I18n.t('DATE_PARAM', { now })).toBe(getText('DATE_PARAM', { now }));
  });

  it('格式化 time 类型的参数 ', () => {
    const meetingTime = new Date();
    expect(I18n.t('TIME_PARAM', { meetingTime })).toBe(getText('TIME_PARAM', { meetingTime }));
  });

  it('格式化 select 类型的参数 ', () => {
    expect(I18n.t('SELECT_PARAM', { gender: 'male' })).toBe(getText('SELECT_PARAM', { gender: 'male' }));
    expect(I18n.t('SELECT_PARAM', { gender: 'female' })).toBe(getText('SELECT_PARAM', { gender: 'female' }));
    expect(I18n.t('SELECT_PARAM', { gender: '???' })).toBe(getText('SELECT_PARAM', { gender: '???' }));
  });

  it('格式化 plural 类型的参数', () => {
    expect(I18n.t('PLURAL_TEXT_0', { count: 1 })).toBe(getText('PLURAL_TEXT_0', { count: 1 }));
    expect(I18n.t('PLURAL_TEXT_0', { count: 3 })).toBe(getText('PLURAL_TEXT_0', { count: 3 }));
    expect(I18n.t('PLURAL_TEXT_0', { count: 100 })).toBe(getText('PLURAL_TEXT_0', { count: 100 }));
    expect(I18n.t('PLURAL_TEXT_1', { num: 1 })).toBe(getText('PLURAL_TEXT_1', { num: 1 }));
    expect(I18n.t('PLURAL_TEXT_1', { num: 100 })).toBe(getText('PLURAL_TEXT_1', { num: 100 }));
    expect(I18n.t('PLURAL_TEXT_2', { num: 1 })).toBe(getText('PLURAL_TEXT_2', { num: 1 }));
    expect(I18n.t('PLURAL_TEXT_2', { num: 100 })).toBe(getText('PLURAL_TEXT_2', { num: 100 }));
    expect(I18n.t('PLURAL_TEXT_3', { num: 1 })).toBe(getText('PLURAL_TEXT_3', { num: 1 }));
    expect(I18n.t('PLURAL_TEXT_3', { num: 100 })).toBe(getText('PLURAL_TEXT_3', { num: 100 }));
  });

  it('格式化 selectordinal 类型的参数', () => {
    expect(I18n.t('SELECTORDINAL', { rank: 1 })).toBe(getText('SELECTORDINAL', { rank: 1 }));
    expect(I18n.t('SELECTORDINAL', { rank: 2 })).toBe(getText('SELECTORDINAL', { rank: 2 }));
    expect(I18n.t('SELECTORDINAL', { rank: 3 })).toBe(getText('SELECTORDINAL', { rank: 3 }));
    expect(I18n.t('SELECTORDINAL', { rank: 100 })).toBe(getText('SELECTORDINAL', { rank: 100 }));
  });

  it('格式化富文本', () => {
    const interpolation = {
      tag: (inner: string) => `<Link>${inner}</Link>`,
      uri: '4399'
    };
    expect(I18n.t('RICH_TEXT', interpolation)).toBe(getText('RICH_TEXT', interpolation));
  });

  it('格式化带转义字符的文本', () => {
    expect(I18n.t('ESCAPE_0')).toBe(getText('ESCAPE_0'));
    expect(I18n.t('ESCAPE_1')).toBe(getText('ESCAPE_1'));
  });
});