import { t, resolveLocale, setI18nProvider, getI18nProvider } from '../../src/i18n';
import type { I18nProvider, SupportedLocale } from '../../src/i18n';

describe('i18n Core', () => {
  // Save and restore the original provider
  let originalProvider: I18nProvider;
  beforeAll(() => {
    originalProvider = getI18nProvider();
  });
  afterAll(() => {
    setI18nProvider(originalProvider);
  });

  describe('t() - Translation Function', () => {
    it('should return English translation for a valid key', () => {
      const result = t('en', 'voice.responses.channelLocked');
      expect(result).toBe('Channel Locked! Only you and invited members can join.'); // i18n-ignore
    });

    it('should return Korean translation for a valid key', () => {
      const result = t('ko', 'voice.responses.channelLocked');
      expect(result).toBe('채널이 잠겼습니다! 초대된 멤버만 참여할 수 있습니다.'); // i18n-ignore
    });

    it('should fallback to English when key is missing in target locale', () => {
      // en.ts has all keys, so simulate a missing key by testing a deep key
      // All keys should exist in ko, so this test verifies the mechanism
      const result = t('en', 'errorTitles.USER_INPUT');
      expect(result).toBe('Please check your input');
    });

    it('should return the key itself when not found in any locale', () => {
      const result = t('en', 'nonExistent.key.path');
      expect(result).toBe('nonExistent.key.path');
    });

    it('should interpolate template variables {{var}}', () => {
      const result = t('en', 'voice.channelReady', { owner: '<@123>' });
      expect(result).toBe('<@123>, your temporary channel is ready! Use the dropdown menu below to manage it.');
    });

    it('should interpolate Korean template variables', () => {
      const result = t('ko', 'voice.channelReady', { owner: '<@456>' });
      expect(result).toBe('<@456>, 임시 채널이 준비되었습니다! 아래 드롭다운 메뉴로 관리하세요.');
    });

    it('should replace multiple occurrences of the same variable', () => {
      // Test with a key that has a variable
      const result = t('en', 'voice.defaultRoomName', { username: 'TestUser' });
      expect(result).toBe("TestUser's Room");
    });

    it('should return Korean default room name', () => {
      const result = t('ko', 'voice.defaultRoomName', { username: '테스터' });
      expect(result).toBe('테스터의 방');
    });

    it('should handle error message lookups', () => {
      const result = t('en', 'errors.E1001.userMessage');
      expect(result).toBe('The user limit value is invalid.');
    });

    it('should handle Korean error message lookups', () => {
      const result = t('ko', 'errors.E1001.userMessage');
      expect(result).toBe('사용자 제한 값이 올바르지 않습니다.');
    });

    it('should handle error resolution lookups', () => {
      const result = t('en', 'errors.E1001.resolution');
      expect(result).toBe('Please enter a number between 0 and 99. (0 = unlimited)');
    });
  });

  describe('resolveLocale() - Locale Resolution', () => {
    it('should return default "en" when no options given', () => {
      const result = resolveLocale();
      expect(result).toBe('en');
    });

    it('should prefer userLocale over guildLocale', () => {
      const result = resolveLocale({
        userLocale: 'ko',
        guildLocale: 'en',
        discordLocale: 'en-US',
      });
      expect(result).toBe('ko');
    });

    it('should use guildLocale when userLocale is null', () => {
      const result = resolveLocale({
        userLocale: null,
        guildLocale: 'ko',
        discordLocale: 'en-US',
      });
      expect(result).toBe('ko');
    });

    it('should use discordLocale when DB settings are null', () => {
      const result = resolveLocale({
        userLocale: null,
        guildLocale: null,
        discordLocale: 'ko',
      });
      expect(result).toBe('ko');
    });

    it('should normalize Discord locale "en-US" to "en"', () => {
      const result = resolveLocale({
        userLocale: null,
        guildLocale: null,
        discordLocale: 'en-US',
      });
      expect(result).toBe('en');
    });

    it('should fallback to "en" for unsupported locale', () => {
      const result = resolveLocale({
        userLocale: 'fr', // Not supported
        guildLocale: null,
        discordLocale: 'ja', // Not supported
      });
      expect(result).toBe('en');
    });
  });

  describe('I18nProvider Interface - Swappable Provider', () => {
    it('should allow swapping to a custom provider', () => {
      const customProvider: I18nProvider = {
        get: (locale: SupportedLocale, key: string) => {
          if (key === 'test.key') return `Custom: ${locale}`;
          return undefined;
        },
        isSupported: (locale: string): locale is SupportedLocale => locale === 'en',
        getSupportedLocales: () => ['en'] as const,
      };

      setI18nProvider(customProvider);
      const result = t('en', 'test.key');
      expect(result).toBe('Custom: en');

      // Restore original
      setI18nProvider(originalProvider);
    });

    it('should fallback correctly with custom provider', () => {
      const customProvider: I18nProvider = {
        get: () => undefined,
        isSupported: (locale: string): locale is SupportedLocale => locale === 'en',
        getSupportedLocales: () => ['en'] as const,
      };

      setI18nProvider(customProvider);
      const result = t('en', 'unknown.key');
      expect(result).toBe('unknown.key'); // Should return key as final fallback

      setI18nProvider(originalProvider);
    });
  });
});
