// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only

import type { AudioDevice } from '@signalapp/ringrtc';
import type { ReactNode } from 'react';
import React, {
  useCallback,
  useEffect,
  useMemo,
  useRef,
  useState,
} from 'react';
import { noop, partition } from 'lodash';
import classNames from 'classnames';
import uuid from 'uuid';
import * as LocaleMatcher from '@formatjs/intl-localematcher';

import type { MediaDeviceSettings } from '../types/Calling';
import type {
  NotificationSettingType,
  SentMediaQualitySettingType,
  ZoomFactorType,
} from '../types/Storage.d';
import type { ThemeSettingType } from '../types/StorageUIKeys';
import type { AnyToast } from '../types/Toast';
import { ToastType } from '../types/Toast';
import type { ConversationType } from '../state/ducks/conversations';
import type {
  ConversationColorType,
  CustomColorType,
  DefaultConversationColorType,
} from '../types/Colors';
import type {
  LocalizerType,
  SentMediaQualityType,
  ThemeType,
} from '../types/Util';

import { Button, ButtonVariant } from './Button';
import { ChatColorPicker } from './ChatColorPicker';
import { Checkbox } from './Checkbox';
import { WidthBreakpoint } from './_util';
import {
  CircleCheckbox,
  Variant as CircleCheckboxVariant,
} from './CircleCheckbox';
import { ConfirmationDialog } from './ConfirmationDialog';
import { DisappearingTimeDialog } from './DisappearingTimeDialog';
import { PhoneNumberDiscoverability } from '../util/phoneNumberDiscoverability';
import { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode';
import { Select } from './Select';
import { Spinner } from './Spinner';
import { ToastManager } from './ToastManager';
import { getCustomColorStyle } from '../util/getCustomColorStyle';
import { shouldNeverBeCalled } from '../util/shouldNeverBeCalled';
import {
  DEFAULT_DURATIONS_IN_SECONDS,
  DEFAULT_DURATIONS_SET,
  format as formatExpirationTimer,
} from '../util/expirationTimer';
import { DurationInSeconds } from '../util/durations';
import { useEscapeHandling } from '../hooks/useEscapeHandling';
import { useUniqueId } from '../hooks/useUniqueId';
import { focusableSelectors } from '../util/focusableSelectors';
import { Modal } from './Modal';
import { SearchInput } from './SearchInput';
import { removeDiacritics } from '../util/removeDiacritics';
import { assertDev } from '../util/assert';

type CheckboxChangeHandlerType = (value: boolean) => unknown;
type SelectChangeHandlerType<T = string | number> = (value: T) => unknown;

export type PropsDataType = {
  // Settings
  blockedCount: number;
  customColors: Record<string, CustomColorType>;
  defaultConversationColor: DefaultConversationColorType;
  deviceName?: string;
  hasAudioNotifications?: boolean;
  hasAutoConvertEmoji: boolean;
  hasAutoDownloadUpdate: boolean;
  hasAutoLaunch: boolean;
  hasCallNotifications: boolean;
  hasCallRingtoneNotification: boolean;
  hasCountMutedConversations: boolean;
  hasHideMenuBar?: boolean;
  hasIncomingCallNotifications: boolean;
  hasLinkPreviews: boolean;
  hasMediaCameraPermissions: boolean;
  hasMediaPermissions: boolean;
  hasMessageAudio: boolean;
  hasMinimizeToAndStartInSystemTray: boolean;
  hasMinimizeToSystemTray: boolean;
  hasNotificationAttention: boolean;
  hasNotifications: boolean;
  hasReadReceipts: boolean;
  hasRelayCalls?: boolean;
  hasSpellCheck: boolean;
  hasStoriesDisabled: boolean;
  hasTextFormatting: boolean;
  hasTypingIndicators: boolean;
  lastSyncTime?: number;
  notificationContent: NotificationSettingType;
  phoneNumber: string | undefined;
  selectedCamera?: string;
  selectedMicrophone?: AudioDevice;
  selectedSpeaker?: AudioDevice;
  sentMediaQualitySetting: SentMediaQualitySettingType;
  themeSetting: ThemeSettingType;
  universalExpireTimer: DurationInSeconds;
  whoCanFindMe: PhoneNumberDiscoverability;
  whoCanSeeMe: PhoneNumberSharingMode;
  zoomFactor: ZoomFactorType;

  // Localization
  availableLocales: ReadonlyArray<string>;
  localeOverride: string | null;
  preferredSystemLocales: ReadonlyArray<string>;
  resolvedLocale: string;

  // Other props
  initialSpellCheckSetting: boolean;

  // Limited support features
  isAutoDownloadUpdatesSupported: boolean;
  isAutoLaunchSupported: boolean;
  isHideMenuBarSupported: boolean;
  isNotificationAttentionSupported: boolean;
  isSyncSupported: boolean;
  isSystemTraySupported: boolean;
  isMinimizeToAndStartInSystemTraySupported: boolean;

  availableCameras: Array<
    Pick<MediaDeviceInfo, 'deviceId' | 'groupId' | 'kind' | 'label'>
  >;
} & Omit<MediaDeviceSettings, 'availableCameras'>;

type PropsFunctionType = {
  // Other props
  addCustomColor: (color: CustomColorType) => unknown;
  closeSettings: () => unknown;
  doDeleteAllData: () => unknown;
  doneRendering: () => unknown;
  editCustomColor: (colorId: string, color: CustomColorType) => unknown;
  getConversationsWithCustomColor: (
    colorId: string
  ) => Promise<Array<ConversationType>>;
  makeSyncRequest: () => unknown;
  removeCustomColor: (colorId: string) => unknown;
  removeCustomColorOnConversations: (colorId: string) => unknown;
  resetAllChatColors: () => unknown;
  resetDefaultChatColor: () => unknown;
  setGlobalDefaultConversationColor: (
    color: ConversationColorType,
    customColorData?: {
      id: string;
      value: CustomColorType;
    }
  ) => unknown;

  // Change handlers
  onAudioNotificationsChange: CheckboxChangeHandlerType;
  onAutoConvertEmojiChange: CheckboxChangeHandlerType;
  onAutoDownloadUpdateChange: CheckboxChangeHandlerType;
  onAutoLaunchChange: CheckboxChangeHandlerType;
  onCallNotificationsChange: CheckboxChangeHandlerType;
  onCallRingtoneNotificationChange: CheckboxChangeHandlerType;
  onCountMutedConversationsChange: CheckboxChangeHandlerType;
  onHasStoriesDisabledChanged: SelectChangeHandlerType<boolean>;
  onHideMenuBarChange: CheckboxChangeHandlerType;
  onIncomingCallNotificationsChange: CheckboxChangeHandlerType;
  onLastSyncTimeChange: (time: number) => unknown;
  onLocaleChange: (locale: string | null) => void;
  onMediaCameraPermissionsChange: CheckboxChangeHandlerType;
  onMediaPermissionsChange: CheckboxChangeHandlerType;
  onMessageAudioChange: CheckboxChangeHandlerType;
  onMinimizeToAndStartInSystemTrayChange: CheckboxChangeHandlerType;
  onMinimizeToSystemTrayChange: CheckboxChangeHandlerType;
  onNotificationAttentionChange: CheckboxChangeHandlerType;
  onNotificationContentChange: SelectChangeHandlerType<NotificationSettingType>;
  onNotificationsChange: CheckboxChangeHandlerType;
  onRelayCallsChange: CheckboxChangeHandlerType;
  onSelectedCameraChange: SelectChangeHandlerType<string | undefined>;
  onSelectedMicrophoneChange: SelectChangeHandlerType<AudioDevice | undefined>;
  onSelectedSpeakerChange: SelectChangeHandlerType<AudioDevice | undefined>;
  onSentMediaQualityChange: SelectChangeHandlerType<SentMediaQualityType>;
  onSpellCheckChange: CheckboxChangeHandlerType;
  onTextFormattingChange: CheckboxChangeHandlerType;
  onThemeChange: SelectChangeHandlerType<ThemeType>;
  onUniversalExpireTimerChange: SelectChangeHandlerType<number>;
  onWhoCanSeeMeChange: SelectChangeHandlerType<PhoneNumberSharingMode>;
  onWhoCanFindMeChange: SelectChangeHandlerType<PhoneNumberDiscoverability>;
  onZoomFactorChange: SelectChangeHandlerType<ZoomFactorType>;

  // Localization
  i18n: LocalizerType;
};

export type PropsType = PropsDataType & PropsFunctionType;

export type PropsPreloadType = Omit<PropsType, 'i18n'>;

enum Page {
  // Accessible through left nav
  General = 'General',
  Appearance = 'Appearance',
  Chats = 'Chats',
  Calls = 'Calls',
  Notifications = 'Notifications',
  Privacy = 'Privacy',

  // Sub pages
  ChatColor = 'ChatColor',
  PNP = 'PNP',
}

enum LanguageDialog {
  Selection,
  Confirmation,
}

const DEFAULT_ZOOM_FACTORS = [
  {
    text: '75%',
    value: 0.75,
  },
  {
    text: '100%',
    value: 1,
  },
  {
    text: '125%',
    value: 1.25,
  },
  {
    text: '150%',
    value: 1.5,
  },
  {
    text: '200%',
    value: 2,
  },
];

export function Preferences({
  addCustomColor,
  availableCameras,
  availableLocales,
  availableMicrophones,
  availableSpeakers,
  blockedCount,
  closeSettings,
  customColors,
  defaultConversationColor,
  deviceName = '',
  doDeleteAllData,
  doneRendering,
  editCustomColor,
  getConversationsWithCustomColor,
  hasAudioNotifications,
  hasAutoConvertEmoji,
  hasAutoDownloadUpdate,
  hasAutoLaunch,
  hasCallNotifications,
  hasCallRingtoneNotification,
  hasCountMutedConversations,
  hasHideMenuBar,
  hasIncomingCallNotifications,
  hasLinkPreviews,
  hasMediaCameraPermissions,
  hasMediaPermissions,
  hasMessageAudio,
  hasMinimizeToAndStartInSystemTray,
  hasMinimizeToSystemTray,
  hasNotificationAttention,
  hasNotifications,
  hasReadReceipts,
  hasRelayCalls,
  hasSpellCheck,
  hasStoriesDisabled,
  hasTextFormatting,
  hasTypingIndicators,
  i18n,
  initialSpellCheckSetting,
  isAutoDownloadUpdatesSupported,
  isAutoLaunchSupported,
  isHideMenuBarSupported,
  isNotificationAttentionSupported,
  isSyncSupported,
  isSystemTraySupported,
  isMinimizeToAndStartInSystemTraySupported,
  lastSyncTime,
  makeSyncRequest,
  notificationContent,
  onAudioNotificationsChange,
  onAutoConvertEmojiChange,
  onAutoDownloadUpdateChange,
  onAutoLaunchChange,
  onCallNotificationsChange,
  onCallRingtoneNotificationChange,
  onCountMutedConversationsChange,
  onHasStoriesDisabledChanged,
  onHideMenuBarChange,
  onIncomingCallNotificationsChange,
  onLastSyncTimeChange,
  onLocaleChange,
  onMediaCameraPermissionsChange,
  onMediaPermissionsChange,
  onMessageAudioChange,
  onMinimizeToAndStartInSystemTrayChange,
  onMinimizeToSystemTrayChange,
  onNotificationAttentionChange,
  onNotificationContentChange,
  onNotificationsChange,
  onRelayCallsChange,
  onSelectedCameraChange,
  onSelectedMicrophoneChange,
  onSelectedSpeakerChange,
  onSentMediaQualityChange,
  onSpellCheckChange,
  onTextFormattingChange,
  onThemeChange,
  onUniversalExpireTimerChange,
  onWhoCanSeeMeChange,
  onWhoCanFindMeChange,
  onZoomFactorChange,
  phoneNumber = '',
  preferredSystemLocales,
  removeCustomColor,
  removeCustomColorOnConversations,
  resetAllChatColors,
  resetDefaultChatColor,
  resolvedLocale,
  selectedCamera,
  selectedMicrophone,
  selectedSpeaker,
  sentMediaQualitySetting,
  setGlobalDefaultConversationColor,
  localeOverride,
  themeSetting,
  universalExpireTimer = DurationInSeconds.ZERO,
  whoCanFindMe,
  whoCanSeeMe,
  zoomFactor,
}: PropsType): JSX.Element {
  const storiesId = useUniqueId();
  const themeSelectId = useUniqueId();
  const zoomSelectId = useUniqueId();
  const languageId = useUniqueId();

  const [confirmDelete, setConfirmDelete] = useState(false);
  const [confirmStoriesOff, setConfirmStoriesOff] = useState(false);
  const [page, setPage] = useState<Page>(Page.General);
  const [showSyncFailed, setShowSyncFailed] = useState(false);
  const [nowSyncing, setNowSyncing] = useState(false);
  const [showDisappearingTimerDialog, setShowDisappearingTimerDialog] =
    useState(false);
  const [languageDialog, setLanguageDialog] = useState<LanguageDialog | null>(
    null
  );
  const [selectedLanguageLocale, setSelectedLanguageLocale] = useState<
    string | null
  >(localeOverride);
  const [languageSearchInput, setLanguageSearchInput] = useState('');
  const [toast, setToast] = useState<AnyToast | undefined>();

  function closeLanguageDialog() {
    setLanguageDialog(null);
    setSelectedLanguageLocale(localeOverride);
  }

  useEffect(() => {
    doneRendering();
  }, [doneRendering]);

  useEscapeHandling(() => {
    if (languageDialog != null) {
      closeLanguageDialog();
    } else {
      closeSettings();
    }
  });

  const onZoomSelectChange = useCallback(
    (value: string) => {
      const number = parseFloat(value);
      onZoomFactorChange(number as unknown as ZoomFactorType);
    },
    [onZoomFactorChange]
  );

  const onAudioInputSelectChange = useCallback(
    (value: string) => {
      if (value === 'undefined') {
        onSelectedMicrophoneChange(undefined);
      } else {
        onSelectedMicrophoneChange(availableMicrophones[parseInt(value, 10)]);
      }
    },
    [onSelectedMicrophoneChange, availableMicrophones]
  );

  const selectors = useMemo(() => focusableSelectors.join(','), []);
  const settingsPaneRef = useRef<HTMLDivElement | null>(null);
  useEffect(() => {
    const settingsPane = settingsPaneRef.current;
    if (!settingsPane) {
      return;
    }

    const elements = settingsPane.querySelectorAll<
      | HTMLAnchorElement
      | HTMLButtonElement
      | HTMLInputElement
      | HTMLSelectElement
      | HTMLTextAreaElement
    >(selectors);
    if (!elements.length) {
      return;
    }
    elements[0]?.focus();
  }, [page, selectors]);

  const onAudioOutputSelectChange = useCallback(
    (value: string) => {
      if (value === 'undefined') {
        onSelectedSpeakerChange(undefined);
      } else {
        onSelectedSpeakerChange(availableSpeakers[parseInt(value, 10)]);
      }
    },
    [onSelectedSpeakerChange, availableSpeakers]
  );

  const localeDisplayNames = window.SignalContext.getLocaleDisplayNames();

  const getLocaleDisplayName = useCallback(
    (inLocale: string, ofLocale: string): string => {
      const displayName = localeDisplayNames[inLocale]?.[ofLocale];
      assertDev(
        displayName != null,
        `Locale display name in ${inLocale} of ${ofLocale} does not exist`
      );
      return (
        displayName ??
        new Intl.DisplayNames(inLocale, {
          type: 'language',
          languageDisplay: 'standard',
          style: 'long',
          fallback: 'code',
        }).of(ofLocale)
      );
    },
    [localeDisplayNames]
  );

  const localeSearchOptions = useMemo(() => {
    const collator = new Intl.Collator('en', { usage: 'sort' });

    const availableLocalesOptions = availableLocales
      .map(locale => {
        const currentLocaleLabel = getLocaleDisplayName(resolvedLocale, locale);
        const matchingLocaleLabel = getLocaleDisplayName(locale, locale);
        return { locale, currentLocaleLabel, matchingLocaleLabel };
      })
      .sort((a, b) => {
        return collator.compare(a.locale, b.locale);
      });

    const [localeOverrideMatches, localeOverrideNonMatches] = partition(
      availableLocalesOptions,
      option => {
        return option.locale === localeOverride;
      }
    );

    const preferredSystemLocaleMatch = LocaleMatcher.match(
      preferredSystemLocales as Array<string>, // bad types
      availableLocales as Array<string>, // bad types
      'en',
      { algorithm: 'best fit' }
    );

    return [
      ...localeOverrideMatches,
      {
        locale: null,
        currentLocaleLabel: i18n('icu:Preferences__Language__SystemLanguage'),
        matchingLocaleLabel: getLocaleDisplayName(
          preferredSystemLocaleMatch,
          preferredSystemLocaleMatch
        ),
      },
      ...localeOverrideNonMatches,
    ];
  }, [
    i18n,
    availableLocales,
    resolvedLocale,
    localeOverride,
    preferredSystemLocales,
    getLocaleDisplayName,
  ]);

  const localeSearchResults = useMemo(() => {
    return localeSearchOptions.filter(option => {
      const input = removeDiacritics(languageSearchInput.trim().toLowerCase());

      if (input === '') {
        return true;
      }

      function isMatch(value: string) {
        return removeDiacritics(value.toLowerCase()).includes(input);
      }

      return (
        isMatch(option.currentLocaleLabel) ||
        (option.matchingLocaleLabel && isMatch(option.matchingLocaleLabel))
      );
    });
  }, [localeSearchOptions, languageSearchInput]);

  let settings: JSX.Element | undefined;
  if (page === Page.General) {
    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__button--general')}
          </div>
        </div>
        <SettingsRow>
          <Control
            left={i18n('icu:Preferences--phone-number')}
            right={phoneNumber}
          />
          <Control
            left={i18n('icu:Preferences--device-name')}
            right={deviceName}
          />
        </SettingsRow>
        <SettingsRow title={i18n('icu:Preferences--system')}>
          {isAutoLaunchSupported && (
            <Checkbox
              checked={hasAutoLaunch}
              label={i18n('icu:autoLaunchDescription')}
              moduleClassName="Preferences__checkbox"
              name="autoLaunch"
              onChange={onAutoLaunchChange}
            />
          )}
          {isHideMenuBarSupported && (
            <Checkbox
              checked={hasHideMenuBar}
              label={i18n('icu:hideMenuBar')}
              moduleClassName="Preferences__checkbox"
              name="hideMenuBar"
              onChange={onHideMenuBarChange}
            />
          )}
          {isSystemTraySupported && (
            <>
              <Checkbox
                checked={hasMinimizeToSystemTray}
                label={i18n('icu:SystemTraySetting__minimize-to-system-tray')}
                moduleClassName="Preferences__checkbox"
                name="system-tray-setting-minimize-to-system-tray"
                onChange={onMinimizeToSystemTrayChange}
              />
              {isMinimizeToAndStartInSystemTraySupported && (
                <Checkbox
                  checked={hasMinimizeToAndStartInSystemTray}
                  disabled={!hasMinimizeToSystemTray}
                  label={i18n(
                    'icu:SystemTraySetting__minimize-to-and-start-in-system-tray'
                  )}
                  moduleClassName="Preferences__checkbox"
                  name="system-tray-setting-minimize-to-and-start-in-system-tray"
                  onChange={onMinimizeToAndStartInSystemTrayChange}
                />
              )}
            </>
          )}
        </SettingsRow>
        <SettingsRow title={i18n('icu:permissions')}>
          <Checkbox
            checked={hasMediaPermissions}
            label={i18n('icu:mediaPermissionsDescription')}
            moduleClassName="Preferences__checkbox"
            name="mediaPermissions"
            onChange={onMediaPermissionsChange}
          />
          <Checkbox
            checked={hasMediaCameraPermissions}
            label={i18n('icu:mediaCameraPermissionsDescription')}
            moduleClassName="Preferences__checkbox"
            name="mediaCameraPermissions"
            onChange={onMediaCameraPermissionsChange}
          />
        </SettingsRow>
        {isAutoDownloadUpdatesSupported && (
          <SettingsRow title={i18n('icu:Preferences--updates')}>
            <Checkbox
              checked={hasAutoDownloadUpdate}
              label={i18n('icu:Preferences__download-update')}
              moduleClassName="Preferences__checkbox"
              name="autoDownloadUpdate"
              onChange={onAutoDownloadUpdateChange}
            />
          </SettingsRow>
        )}
      </>
    );
  } else if (page === Page.Appearance) {
    let zoomFactors = DEFAULT_ZOOM_FACTORS;

    if (!zoomFactors.some(({ value }) => value === zoomFactor)) {
      zoomFactors = [
        ...zoomFactors,
        {
          text: `${Math.round(zoomFactor * 100)}%`,
          value: zoomFactor,
        },
      ].sort((a, b) => a.value - b.value);
    }

    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__button--appearance')}
          </div>
        </div>
        <SettingsRow>
          <Control
            icon="Preferences__LanguageIcon"
            left={i18n('icu:Preferences__Language__Label')}
            right={
              <span
                className="Preferences__LanguageButton"
                lang={localeOverride ?? resolvedLocale}
              >
                {localeOverride != null
                  ? getLocaleDisplayName(resolvedLocale, localeOverride)
                  : i18n('icu:Preferences__Language__SystemLanguage')}
              </span>
            }
            onClick={() => {
              setLanguageDialog(LanguageDialog.Selection);
            }}
          />
          {languageDialog === LanguageDialog.Selection && (
            <Modal
              i18n={i18n}
              modalName="Preferences__LanguageModal"
              moduleClassName="Preferences__LanguageModal"
              padded={false}
              onClose={closeLanguageDialog}
              title={i18n('icu:Preferences__Language__ModalTitle')}
              modalHeaderChildren={
                <SearchInput
                  i18n={i18n}
                  value={languageSearchInput}
                  placeholder={i18n(
                    'icu:Preferences__Language__SearchLanguages'
                  )}
                  moduleClassName="Preferences__LanguageModal__SearchInput"
                  onChange={event => {
                    setLanguageSearchInput(event.currentTarget.value);
                  }}
                />
              }
              modalFooter={
                <>
                  <Button
                    variant={ButtonVariant.Secondary}
                    onClick={closeLanguageDialog}
                  >
                    {i18n('icu:cancel')}
                  </Button>
                  <Button
                    variant={ButtonVariant.Primary}
                    disabled={selectedLanguageLocale === localeOverride}
                    onClick={() => {
                      setLanguageDialog(LanguageDialog.Confirmation);
                    }}
                  >
                    {i18n('icu:Preferences__LanguageModal__Set')}
                  </Button>
                </>
              }
            >
              {localeSearchResults.length === 0 && (
                <div className="Preferences__LanguageModal__NoResults">
                  {i18n('icu:Preferences__Language__NoResults', {
                    searchTerm: languageSearchInput.trim(),
                  })}
                </div>
              )}
              {localeSearchResults.map(option => {
                const id = `${languageId}:${option.locale ?? 'system'}`;
                const isSelected = option.locale === selectedLanguageLocale;
                return (
                  <button
                    key={id}
                    type="button"
                    className="Preferences__LanguageModal__Item"
                    onClick={() => {
                      setSelectedLanguageLocale(option.locale);
                    }}
                    aria-pressed={isSelected}
                  >
                    <span className="Preferences__LanguageModal__Item__Inner">
                      <span className="Preferences__LanguageModal__Item__Label">
                        <span className="Preferences__LanguageModal__Item__Current">
                          {option.currentLocaleLabel}
                        </span>
                        {option.matchingLocaleLabel != null && (
                          <span
                            lang={option.locale ?? resolvedLocale}
                            className="Preferences__LanguageModal__Item__Matching"
                          >
                            {option.matchingLocaleLabel}
                          </span>
                        )}
                      </span>
                      {isSelected && (
                        <span className="Preferences__LanguageModal__Item__Check" />
                      )}
                    </span>
                  </button>
                );
              })}
            </Modal>
          )}
          {languageDialog === LanguageDialog.Confirmation && (
            <ConfirmationDialog
              dialogName="Preferences__Language"
              i18n={i18n}
              title={i18n('icu:Preferences__LanguageModal__Restart__Title')}
              onCancel={closeLanguageDialog}
              onClose={closeLanguageDialog}
              cancelText={i18n('icu:cancel')}
              actions={[
                {
                  text: i18n('icu:Preferences__LanguageModal__Restart__Button'),
                  style: 'affirmative',
                  action: () => {
                    onLocaleChange(selectedLanguageLocale);
                  },
                },
              ]}
            >
              {i18n('icu:Preferences__LanguageModal__Restart__Description')}
            </ConfirmationDialog>
          )}
          <Control
            icon
            left={
              <label htmlFor={themeSelectId}>
                {i18n('icu:Preferences--theme')}
              </label>
            }
            right={
              <Select
                id={themeSelectId}
                onChange={onThemeChange}
                options={[
                  {
                    text: i18n('icu:themeSystem'),
                    value: 'system',
                  },
                  {
                    text: i18n('icu:themeLight'),
                    value: 'light',
                  },
                  {
                    text: i18n('icu:themeDark'),
                    value: 'dark',
                  },
                ]}
                value={themeSetting}
              />
            }
          />
          <Control
            icon
            left={i18n('icu:showChatColorEditor')}
            onClick={() => {
              setPage(Page.ChatColor);
            }}
            right={
              <div
                className={`ConversationDetails__chat-color ConversationDetails__chat-color--${defaultConversationColor.color}`}
                style={{
                  ...getCustomColorStyle(
                    defaultConversationColor.customColorData?.value
                  ),
                }}
              />
            }
          />
          <Control
            icon
            left={
              <label htmlFor={zoomSelectId}>
                {i18n('icu:Preferences--zoom')}
              </label>
            }
            right={
              <Select
                id={zoomSelectId}
                onChange={onZoomSelectChange}
                options={zoomFactors}
                value={zoomFactor}
              />
            }
          />
        </SettingsRow>
      </>
    );
  } else if (page === Page.Chats) {
    let spellCheckDirtyText: string | undefined;
    if (initialSpellCheckSetting !== hasSpellCheck) {
      spellCheckDirtyText = hasSpellCheck
        ? i18n('icu:spellCheckWillBeEnabled')
        : i18n('icu:spellCheckWillBeDisabled');
    }

    const lastSyncDate = new Date(lastSyncTime || 0);

    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__button--chats')}
          </div>
        </div>
        <SettingsRow title={i18n('icu:Preferences__button--chats')}>
          <Checkbox
            checked={hasSpellCheck}
            description={spellCheckDirtyText}
            label={i18n('icu:spellCheckDescription')}
            moduleClassName="Preferences__checkbox"
            name="spellcheck"
            onChange={onSpellCheckChange}
          />
          <Checkbox
            checked={hasTextFormatting}
            label={i18n('icu:textFormattingDescription')}
            moduleClassName="Preferences__checkbox"
            name="textFormatting"
            onChange={onTextFormattingChange}
          />
          <Checkbox
            checked={hasLinkPreviews}
            description={i18n('icu:Preferences__link-previews--description')}
            disabled
            label={i18n('icu:Preferences__link-previews--title')}
            moduleClassName="Preferences__checkbox"
            name="linkPreviews"
            onChange={noop}
          />
          <Checkbox
            checked={hasAutoConvertEmoji}
            description={i18n(
              'icu:Preferences__auto-convert-emoji--description'
            )}
            label={i18n('icu:Preferences__auto-convert-emoji--title')}
            moduleClassName="Preferences__checkbox"
            name="autoConvertEmoji"
            onChange={onAutoConvertEmojiChange}
          />
          <Control
            left={i18n('icu:Preferences__sent-media-quality')}
            right={
              <Select
                onChange={onSentMediaQualityChange}
                options={[
                  {
                    text: i18n('icu:sentMediaQualityStandard'),
                    value: 'standard',
                  },
                  {
                    text: i18n('icu:sentMediaQualityHigh'),
                    value: 'high',
                  },
                ]}
                value={sentMediaQualitySetting}
              />
            }
          />
        </SettingsRow>
        {isSyncSupported && (
          <SettingsRow>
            <Control
              left={
                <>
                  <div>{i18n('icu:sync')}</div>
                  <div className="Preferences__description">
                    {i18n('icu:syncExplanation')}{' '}
                    {i18n('icu:Preferences--lastSynced', {
                      date: lastSyncDate.toLocaleDateString(),
                      time: lastSyncDate.toLocaleTimeString(),
                    })}
                  </div>
                  {showSyncFailed && (
                    <div className="Preferences__description Preferences__description--error">
                      {i18n('icu:syncFailed')}
                    </div>
                  )}
                </>
              }
              right={
                <div className="Preferences__right-button">
                  <Button
                    aria-label={
                      nowSyncing ? i18n('icu:syncing') : i18n('icu:syncNow')
                    }
                    aria-live="polite"
                    disabled={nowSyncing}
                    onClick={async () => {
                      setShowSyncFailed(false);
                      setNowSyncing(true);
                      try {
                        await makeSyncRequest();
                        onLastSyncTimeChange(Date.now());
                      } catch (err) {
                        setShowSyncFailed(true);
                      } finally {
                        setNowSyncing(false);
                      }
                    }}
                    variant={ButtonVariant.SecondaryAffirmative}
                  >
                    {nowSyncing ? (
                      <Spinner svgSize="small" />
                    ) : (
                      i18n('icu:syncNow')
                    )}
                  </Button>
                </div>
              }
            />
          </SettingsRow>
        )}
      </>
    );
  } else if (page === Page.Calls) {
    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__button--calls')}
          </div>
        </div>
        <SettingsRow title={i18n('icu:calling')}>
          <Checkbox
            checked={hasIncomingCallNotifications}
            label={i18n('icu:incomingCallNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="incomingCallNotification"
            onChange={onIncomingCallNotificationsChange}
          />
          <Checkbox
            checked={hasCallRingtoneNotification}
            label={i18n('icu:callRingtoneNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="callRingtoneNotification"
            onChange={onCallRingtoneNotificationChange}
          />
        </SettingsRow>
        <SettingsRow title={i18n('icu:Preferences__devices')}>
          <Control
            left={
              <>
                <label className="Preferences__select-title" htmlFor="video">
                  {i18n('icu:callingDeviceSelection__label--video')}
                </label>
                <Select
                  ariaLabel={i18n('icu:callingDeviceSelection__label--video')}
                  disabled={!availableCameras.length}
                  moduleClassName="Preferences__select"
                  name="video"
                  onChange={onSelectedCameraChange}
                  options={
                    availableCameras.length
                      ? availableCameras.map(device => ({
                          text: localizeDefault(i18n, device.label),
                          value: device.deviceId,
                        }))
                      : [
                          {
                            text: i18n(
                              'icu:callingDeviceSelection__select--no-device'
                            ),
                            value: 'undefined',
                          },
                        ]
                  }
                  value={selectedCamera}
                />
              </>
            }
            right={<div />}
          />
          <Control
            left={
              <>
                <label
                  className="Preferences__select-title"
                  htmlFor="audio-input"
                >
                  {i18n('icu:callingDeviceSelection__label--audio-input')}
                </label>
                <Select
                  ariaLabel={i18n(
                    'icu:callingDeviceSelection__label--audio-input'
                  )}
                  disabled={!availableMicrophones.length}
                  moduleClassName="Preferences__select"
                  name="audio-input"
                  onChange={onAudioInputSelectChange}
                  options={
                    availableMicrophones.length
                      ? availableMicrophones.map(device => ({
                          text: localizeDefault(i18n, device.name),
                          value: device.index,
                        }))
                      : [
                          {
                            text: i18n(
                              'icu:callingDeviceSelection__select--no-device'
                            ),
                            value: 'undefined',
                          },
                        ]
                  }
                  value={selectedMicrophone?.index}
                />
              </>
            }
            right={<div />}
          />
          <Control
            left={
              <>
                <label
                  className="Preferences__select-title"
                  htmlFor="audio-output"
                >
                  {i18n('icu:callingDeviceSelection__label--audio-output')}
                </label>
                <Select
                  ariaLabel={i18n(
                    'icu:callingDeviceSelection__label--audio-output'
                  )}
                  disabled={!availableSpeakers.length}
                  moduleClassName="Preferences__select"
                  name="audio-output"
                  onChange={onAudioOutputSelectChange}
                  options={
                    availableSpeakers.length
                      ? availableSpeakers.map(device => ({
                          text: localizeDefault(i18n, device.name),
                          value: device.index,
                        }))
                      : [
                          {
                            text: i18n(
                              'icu:callingDeviceSelection__select--no-device'
                            ),
                            value: 'undefined',
                          },
                        ]
                  }
                  value={selectedSpeaker?.index}
                />
              </>
            }
            right={<div />}
          />
        </SettingsRow>
        <SettingsRow title={i18n('icu:Preferences--advanced')}>
          <Checkbox
            checked={hasRelayCalls}
            description={i18n('icu:alwaysRelayCallsDetail')}
            label={i18n('icu:alwaysRelayCallsDescription')}
            moduleClassName="Preferences__checkbox"
            name="relayCalls"
            onChange={onRelayCallsChange}
          />
        </SettingsRow>
      </>
    );
  } else if (page === Page.Notifications) {
    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__button--notifications')}
          </div>
        </div>
        <SettingsRow>
          <Checkbox
            checked={hasNotifications}
            label={i18n('icu:Preferences__enable-notifications')}
            moduleClassName="Preferences__checkbox"
            name="notifications"
            onChange={onNotificationsChange}
          />
          <Checkbox
            checked={hasCallNotifications}
            label={i18n('icu:callSystemNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="callSystemNotification"
            onChange={onCallNotificationsChange}
          />
          {isNotificationAttentionSupported && (
            <Checkbox
              checked={hasNotificationAttention}
              label={i18n('icu:notificationDrawAttention')}
              moduleClassName="Preferences__checkbox"
              name="notificationDrawAttention"
              onChange={onNotificationAttentionChange}
            />
          )}
          <Checkbox
            checked={hasCountMutedConversations}
            label={i18n('icu:countMutedConversationsDescription')}
            moduleClassName="Preferences__checkbox"
            name="countMutedConversations"
            onChange={onCountMutedConversationsChange}
          />
        </SettingsRow>
        <SettingsRow>
          <Control
            left={i18n('icu:Preferences--notification-content')}
            right={
              <Select
                ariaLabel={i18n('icu:Preferences--notification-content')}
                disabled={!hasNotifications}
                onChange={onNotificationContentChange}
                options={[
                  {
                    text: i18n('icu:nameAndMessage'),
                    value: 'message',
                  },
                  {
                    text: i18n('icu:nameOnly'),
                    value: 'name',
                  },
                  {
                    text: i18n('icu:noNameOrMessage'),
                    value: 'count',
                  },
                ]}
                value={notificationContent}
              />
            }
          />
        </SettingsRow>
        <SettingsRow>
          <Checkbox
            checked={hasAudioNotifications}
            label={i18n('icu:audioNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="audioNotification"
            onChange={onAudioNotificationsChange}
          />
          <Checkbox
            checked={hasMessageAudio}
            description={i18n('icu:Preferences__message-audio-description')}
            label={i18n('icu:Preferences__message-audio-title')}
            moduleClassName="Preferences__checkbox"
            name="messageAudio"
            onChange={onMessageAudioChange}
          />
        </SettingsRow>
      </>
    );
  } else if (page === Page.Privacy) {
    const isCustomDisappearingMessageValue =
      !DEFAULT_DURATIONS_SET.has(universalExpireTimer);

    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__button--privacy')}
          </div>
        </div>
        <button
          type="button"
          className="Preferences__link"
          onClick={() => setPage(Page.PNP)}
        >
          <h3 className="Preferences__padding">
            {i18n('icu:Preferences__pnp__row--title')}
          </h3>
          <div className="Preferences__padding Preferences__description">
            {i18n('icu:Preferences__pnp__row--body')}
          </div>
        </button>
        <SettingsRow>
          <Control
            left={i18n('icu:Preferences--blocked')}
            right={i18n('icu:Preferences--blocked-count', {
              num: blockedCount,
            })}
          />
        </SettingsRow>
        <SettingsRow title={i18n('icu:Preferences--messaging')}>
          <Checkbox
            checked={hasReadReceipts}
            disabled
            label={i18n('icu:Preferences--read-receipts')}
            moduleClassName="Preferences__checkbox"
            name="readReceipts"
            onChange={noop}
          />
          <Checkbox
            checked={hasTypingIndicators}
            disabled
            label={i18n('icu:Preferences--typing-indicators')}
            moduleClassName="Preferences__checkbox"
            name="typingIndicators"
            onChange={noop}
          />
          <div className="Preferences__padding">
            <div className="Preferences__description">
              {i18n('icu:Preferences__privacy--description')}
            </div>
          </div>
        </SettingsRow>
        {showDisappearingTimerDialog && (
          <DisappearingTimeDialog
            i18n={i18n}
            initialValue={universalExpireTimer}
            onClose={() => setShowDisappearingTimerDialog(false)}
            onSubmit={onUniversalExpireTimerChange}
          />
        )}
        <SettingsRow title={i18n('icu:disappearingMessages')}>
          <Control
            left={
              <>
                <div>
                  {i18n('icu:settings__DisappearingMessages__timer__label')}
                </div>
                <div className="Preferences__description">
                  {i18n('icu:settings__DisappearingMessages__footer')}
                </div>
              </>
            }
            right={
              <Select
                ariaLabel={i18n(
                  'icu:settings__DisappearingMessages__timer__label'
                )}
                onChange={value => {
                  if (
                    value === String(universalExpireTimer) ||
                    value === '-1'
                  ) {
                    setShowDisappearingTimerDialog(true);
                    return;
                  }

                  onUniversalExpireTimerChange(parseInt(value, 10));
                }}
                options={DEFAULT_DURATIONS_IN_SECONDS.map(seconds => {
                  const text = formatExpirationTimer(i18n, seconds, {
                    capitalizeOff: true,
                  });
                  return {
                    value: seconds,
                    text,
                  };
                }).concat([
                  {
                    value: isCustomDisappearingMessageValue
                      ? universalExpireTimer
                      : DurationInSeconds.fromSeconds(-1),
                    text: isCustomDisappearingMessageValue
                      ? formatExpirationTimer(i18n, universalExpireTimer)
                      : i18n('icu:selectedCustomDisappearingTimeOption'),
                  },
                ])}
                value={universalExpireTimer}
              />
            }
          />
        </SettingsRow>
        <SettingsRow title={i18n('icu:Stories__title')}>
          <Control
            left={
              <label htmlFor={storiesId}>
                <div>{i18n('icu:Stories__settings-toggle--title')}</div>
                <div className="Preferences__description">
                  {i18n('icu:Stories__settings-toggle--description')}
                </div>
              </label>
            }
            right={
              hasStoriesDisabled ? (
                <Button
                  onClick={() => onHasStoriesDisabledChanged(false)}
                  variant={ButtonVariant.Secondary}
                >
                  {i18n('icu:Preferences__turn-stories-on')}
                </Button>
              ) : (
                <Button
                  className="Preferences__stories-off"
                  onClick={() => setConfirmStoriesOff(true)}
                  variant={ButtonVariant.SecondaryDestructive}
                >
                  {i18n('icu:Preferences__turn-stories-off')}
                </Button>
              )
            }
          />
        </SettingsRow>
        <SettingsRow>
          <Control
            left={
              <>
                <div>{i18n('icu:clearDataHeader')}</div>
                <div className="Preferences__description">
                  {i18n('icu:clearDataExplanation')}
                </div>
              </>
            }
            right={
              <div className="Preferences__right-button">
                <Button
                  onClick={() => setConfirmDelete(true)}
                  variant={ButtonVariant.SecondaryDestructive}
                >
                  {i18n('icu:clearDataButton')}
                </Button>
              </div>
            }
          />
        </SettingsRow>
        {confirmDelete ? (
          <ConfirmationDialog
            dialogName="Preference.deleteAllData"
            actions={[
              {
                action: doDeleteAllData,
                style: 'negative',
                text: i18n('icu:clearDataButton'),
              },
            ]}
            i18n={i18n}
            onClose={() => {
              setConfirmDelete(false);
            }}
            title={i18n('icu:deleteAllDataHeader')}
          >
            {i18n('icu:deleteAllDataBody')}
          </ConfirmationDialog>
        ) : null}
        {confirmStoriesOff ? (
          <ConfirmationDialog
            dialogName="Preference.turnStoriesOff"
            actions={[
              {
                action: () => onHasStoriesDisabledChanged(true),
                style: 'negative',
                text: i18n('icu:Preferences__turn-stories-off--action'),
              },
            ]}
            i18n={i18n}
            onClose={() => {
              setConfirmStoriesOff(false);
            }}
          >
            {i18n('icu:Preferences__turn-stories-off--body')}
          </ConfirmationDialog>
        ) : null}
      </>
    );
  } else if (page === Page.ChatColor) {
    settings = (
      <>
        <div className="Preferences__title">
          <button
            aria-label={i18n('icu:goBack')}
            className="Preferences__back-icon"
            onClick={() => setPage(Page.Appearance)}
            type="button"
          />
          <div className="Preferences__title--header">
            {i18n('icu:ChatColorPicker__menu-title')}
          </div>
        </div>
        <ChatColorPicker
          customColors={customColors}
          getConversationsWithCustomColor={getConversationsWithCustomColor}
          i18n={i18n}
          isGlobal
          selectedColor={defaultConversationColor.color}
          selectedCustomColor={defaultConversationColor.customColorData || {}}
          // actions
          addCustomColor={addCustomColor}
          colorSelected={noop}
          editCustomColor={editCustomColor}
          removeCustomColor={removeCustomColor}
          removeCustomColorOnConversations={removeCustomColorOnConversations}
          resetAllChatColors={resetAllChatColors}
          resetDefaultChatColor={resetDefaultChatColor}
          setGlobalDefaultConversationColor={setGlobalDefaultConversationColor}
        />
      </>
    );
  } else if (page === Page.PNP) {
    let sharingDescription: string;

    if (whoCanSeeMe === PhoneNumberSharingMode.Everybody) {
      sharingDescription = i18n(
        'icu:Preferences__pnp__sharing--description--everyone'
      );
    } else if (whoCanFindMe === PhoneNumberDiscoverability.Discoverable) {
      sharingDescription = i18n(
        'icu:Preferences__pnp__sharing--description--nobody'
      );
    } else {
      sharingDescription = i18n(
        'icu:Preferences__pnp__sharing--description--nobody--not-discoverable'
      );
    }
    settings = (
      <>
        <div className="Preferences__title">
          <button
            aria-label={i18n('icu:goBack')}
            className="Preferences__back-icon"
            onClick={() => setPage(Page.Privacy)}
            type="button"
          />
          <div className="Preferences__title--header">
            {i18n('icu:Preferences__pnp--page-title')}
          </div>
        </div>

        <SettingsRow
          title={i18n('icu:Preferences__pnp__sharing--title')}
          className={classNames('Preferences__settings-row--pnp-sharing', {
            'Preferences__settings-row--pnp-sharing--nobody':
              whoCanSeeMe === PhoneNumberSharingMode.Nobody,
          })}
        >
          <SettingsRadio
            onChange={onWhoCanSeeMeChange}
            options={[
              {
                text: i18n('icu:Preferences__pnp__sharing__everyone'),
                value: PhoneNumberSharingMode.Everybody,
              },
              {
                text: i18n('icu:Preferences__pnp__sharing__nobody'),
                value: PhoneNumberSharingMode.Nobody,
              },
            ]}
            value={whoCanSeeMe}
          />
          <div className="Preferences__padding">
            <div className="Preferences__description">{sharingDescription}</div>
          </div>
        </SettingsRow>

        <SettingsRow
          title={i18n('icu:Preferences__pnp__discoverability--title')}
        >
          <SettingsRadio
            onChange={onWhoCanFindMeChange}
            options={[
              {
                text: i18n('icu:Preferences__pnp__discoverability__everyone'),
                value: PhoneNumberDiscoverability.Discoverable,
              },
              {
                text: i18n('icu:Preferences__pnp__discoverability__nobody'),
                value: PhoneNumberDiscoverability.NotDiscoverable,
                readOnly: whoCanSeeMe === PhoneNumberSharingMode.Everybody,
                onClick:
                  whoCanSeeMe === PhoneNumberSharingMode.Everybody
                    ? () =>
                        setToast({ toastType: ToastType.WhoCanFindMeReadOnly })
                    : noop,
              },
            ]}
            value={whoCanFindMe}
          />
          <div className="Preferences__padding">
            <div className="Preferences__description">
              {whoCanFindMe === PhoneNumberDiscoverability.Discoverable
                ? i18n(
                    'icu:Preferences__pnp__discoverability--description--everyone'
                  )
                : i18n(
                    'icu:Preferences__pnp__discoverability--description--nobody'
                  )}
            </div>
          </div>
        </SettingsRow>
      </>
    );
  }

  return (
    <>
      <div className="module-title-bar-drag-area" />
      <div className="Preferences">
        <div className="Preferences__page-selector">
          <button
            type="button"
            className={classNames({
              Preferences__button: true,
              'Preferences__button--general': true,
              'Preferences__button--selected': page === Page.General,
            })}
            onClick={() => setPage(Page.General)}
          >
            {i18n('icu:Preferences__button--general')}
          </button>
          <button
            type="button"
            className={classNames({
              Preferences__button: true,
              'Preferences__button--appearance': true,
              'Preferences__button--selected':
                page === Page.Appearance || page === Page.ChatColor,
            })}
            onClick={() => setPage(Page.Appearance)}
          >
            {i18n('icu:Preferences__button--appearance')}
          </button>
          <button
            type="button"
            className={classNames({
              Preferences__button: true,
              'Preferences__button--chats': true,
              'Preferences__button--selected': page === Page.Chats,
            })}
            onClick={() => setPage(Page.Chats)}
          >
            {i18n('icu:Preferences__button--chats')}
          </button>
          <button
            type="button"
            className={classNames({
              Preferences__button: true,
              'Preferences__button--calls': true,
              'Preferences__button--selected': page === Page.Calls,
            })}
            onClick={() => setPage(Page.Calls)}
          >
            {i18n('icu:Preferences__button--calls')}
          </button>
          <button
            type="button"
            className={classNames({
              Preferences__button: true,
              'Preferences__button--notifications': true,
              'Preferences__button--selected': page === Page.Notifications,
            })}
            onClick={() => setPage(Page.Notifications)}
          >
            {i18n('icu:Preferences__button--notifications')}
          </button>

          <button
            type="button"
            className={classNames({
              Preferences__button: true,
              'Preferences__button--privacy': true,
              'Preferences__button--selected':
                page === Page.Privacy || page === Page.PNP,
            })}
            onClick={() => setPage(Page.Privacy)}
          >
            {i18n('icu:Preferences__button--privacy')}
          </button>
        </div>
        <div className="Preferences__settings-pane" ref={settingsPaneRef}>
          {settings}
        </div>
      </div>
      <ToastManager
        OS="unused"
        hideToast={() => setToast(undefined)}
        i18n={i18n}
        onShowDebugLog={shouldNeverBeCalled}
        onUndoArchive={shouldNeverBeCalled}
        openFileInFolder={shouldNeverBeCalled}
        toast={toast}
        containerWidthBreakpoint={WidthBreakpoint.Narrow}
      />
    </>
  );
}

function SettingsRow({
  children,
  title,
  className,
}: {
  children: ReactNode;
  title?: string;
  className?: string;
}): JSX.Element {
  return (
    <fieldset className={classNames('Preferences__settings-row', className)}>
      {title && <legend className="Preferences__padding">{title}</legend>}
      {children}
    </fieldset>
  );
}

function Control({
  icon,
  left,
  onClick,
  right,
}: {
  /** A className or `true` to leave room for icon */
  icon?: string | true;
  left: ReactNode;
  onClick?: () => unknown;
  right: ReactNode;
}): JSX.Element {
  const content = (
    <>
      {icon && (
        <div
          className={classNames(
            'Preferences__control--icon',
            icon === true ? null : icon
          )}
        />
      )}
      <div className="Preferences__control--key">{left}</div>
      <div className="Preferences__control--value">{right}</div>
    </>
  );

  if (onClick) {
    return (
      <button
        className="Preferences__control Preferences__control--clickable"
        type="button"
        onClick={onClick}
      >
        {content}
      </button>
    );
  }

  return <div className="Preferences__control">{content}</div>;
}

type SettingsRadioOptionType<Enum> = Readonly<{
  text: string;
  value: Enum;
  readOnly?: boolean;
  onClick?: () => void;
}>;

function SettingsRadio<Enum>({
  value,
  options,
  onChange,
}: {
  value: Enum;
  options: ReadonlyArray<SettingsRadioOptionType<Enum>>;
  onChange: (value: Enum) => void;
}): JSX.Element {
  const htmlIds = useMemo(() => {
    return Array.from({ length: options.length }, () => uuid());
  }, [options.length]);

  return (
    <div className="Preferences__padding">
      {options.map(({ text, value: optionValue, readOnly, onClick }, i) => {
        const htmlId = htmlIds[i];
        return (
          <label
            className={classNames('Preferences__settings-radio__label', {
              'Preferences__settings-radio__label--readonly': readOnly,
            })}
            key={htmlId}
            htmlFor={htmlId}
          >
            <CircleCheckbox
              isRadio
              variant={CircleCheckboxVariant.Small}
              id={htmlId}
              checked={value === optionValue}
              onClick={onClick}
              onChange={readOnly ? noop : () => onChange(optionValue)}
            />
            {text}
          </label>
        );
      })}
    </div>
  );
}

function localizeDefault(i18n: LocalizerType, deviceLabel: string): string {
  return deviceLabel.toLowerCase().startsWith('default')
    ? deviceLabel.replace(
        /default/i,
        i18n('icu:callingDeviceSelection__select--default')
      )
    : deviceLabel;
}
