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

import React, { ReactNode, useEffect, useState, useCallback } from 'react';
import { noop } from 'lodash';
import classNames from 'classnames';
import type { AudioDevice } from 'ringrtc';

import type { MediaDeviceSettings } from '../types/Calling';
import {
  ZoomFactorType,
  ThemeSettingType,
  NotificationSettingType,
} from '../types/Storage.d';
import { Button, ButtonVariant } from './Button';
import { ChatColorPicker } from './ChatColorPicker';
import { Checkbox } from './Checkbox';
import { ConfirmationDialog } from './ConfirmationDialog';
import { ConversationType } from '../state/ducks/conversations';
import {
  ConversationColorType,
  CustomColorType,
  DefaultConversationColorType,
} from '../types/Colors';
import { DisappearingTimeDialog } from './DisappearingTimeDialog';
import { LocalizerType, ThemeType } from '../types/Util';
import { PhoneNumberDiscoverability } from '../util/phoneNumberDiscoverability';
import { PhoneNumberSharingMode } from '../util/phoneNumberSharingMode';
import { Select } from './Select';
import { Spinner } from './Spinner';
import { getCustomColorStyle } from '../util/getCustomColorStyle';
import {
  DEFAULT_DURATIONS_IN_SECONDS,
  DEFAULT_DURATIONS_SET,
  format as formatExpirationTimer,
} from '../util/expirationTimer';
import { useEscapeHandling } from '../hooks/useEscapeHandling';

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

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

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

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

  // Change handlers
  onAudioNotificationsChange: CheckboxChangeHandlerType;
  onAutoDownloadUpdateChange: CheckboxChangeHandlerType;
  onAutoLaunchChange: CheckboxChangeHandlerType;
  onCallNotificationsChange: CheckboxChangeHandlerType;
  onCallRingtoneNotificationChange: CheckboxChangeHandlerType;
  onCountMutedConversationsChange: CheckboxChangeHandlerType;
  onHideMenuBarChange: CheckboxChangeHandlerType;
  onIncomingCallNotificationsChange: CheckboxChangeHandlerType;
  onLastSyncTimeChange: (time: number) => unknown;
  onMediaCameraPermissionsChange: CheckboxChangeHandlerType;
  onMediaPermissionsChange: 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>;
  onSpellCheckChange: CheckboxChangeHandlerType;
  onThemeChange: SelectChangeHandlerType<ThemeType>;
  onUniversalExpireTimerChange: SelectChangeHandlerType<number>;
  onZoomFactorChange: SelectChangeHandlerType<ZoomFactorType>;

  availableCameras: Array<
    Pick<MediaDeviceInfo, 'deviceId' | 'groupId' | 'kind' | 'label'>
  >;

  // Localization
  i18n: LocalizerType;
} & Omit<MediaDeviceSettings, 'availableCameras'>;

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

  // Sub pages
  ChatColor = 'ChatColor',
}

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 const Preferences = ({
  addCustomColor,
  availableCameras,
  availableMicrophones,
  availableSpeakers,
  blockedCount,
  closeSettings,
  customColors,
  defaultConversationColor,
  deviceName = '',
  doDeleteAllData,
  doneRendering,
  editCustomColor,
  getConversationsWithCustomColor,
  hasAudioNotifications,
  hasAutoDownloadUpdate,
  hasAutoLaunch,
  hasCallNotifications,
  hasCallRingtoneNotification,
  hasCountMutedConversations,
  hasHideMenuBar,
  hasIncomingCallNotifications,
  hasLinkPreviews,
  hasMediaCameraPermissions,
  hasMediaPermissions,
  hasMinimizeToAndStartInSystemTray,
  hasMinimizeToSystemTray,
  hasNotificationAttention,
  hasNotifications,
  hasReadReceipts,
  hasRelayCalls,
  hasSpellCheck,
  hasTypingIndicators,
  i18n,
  initialSpellCheckSetting,
  isAudioNotificationsSupported,
  isAutoDownloadUpdatesSupported,
  isAutoLaunchSupported,
  isHideMenuBarSupported,
  isPhoneNumberSharingSupported,
  isNotificationAttentionSupported,
  isSyncSupported,
  isSystemTraySupported,
  lastSyncTime,
  makeSyncRequest,
  notificationContent,
  onAudioNotificationsChange,
  onAutoDownloadUpdateChange,
  onAutoLaunchChange,
  onCallNotificationsChange,
  onCallRingtoneNotificationChange,
  onCountMutedConversationsChange,
  onHideMenuBarChange,
  onIncomingCallNotificationsChange,
  onLastSyncTimeChange,
  onMediaCameraPermissionsChange,
  onMediaPermissionsChange,
  onMinimizeToAndStartInSystemTrayChange,
  onMinimizeToSystemTrayChange,
  onNotificationAttentionChange,
  onNotificationContentChange,
  onNotificationsChange,
  onRelayCallsChange,
  onSelectedCameraChange,
  onSelectedMicrophoneChange,
  onSelectedSpeakerChange,
  onSpellCheckChange,
  onThemeChange,
  onUniversalExpireTimerChange,
  onZoomFactorChange,
  removeCustomColor,
  removeCustomColorOnConversations,
  resetAllChatColors,
  resetDefaultChatColor,
  selectedCamera,
  selectedMicrophone,
  selectedSpeaker,
  setGlobalDefaultConversationColor,
  theme,
  themeSetting,
  universalExpireTimer = 0,
  whoCanFindMe,
  whoCanSeeMe,
  zoomFactor,
}: PropsType): JSX.Element => {
  const [confirmDelete, setConfirmDelete] = useState(false);
  const [page, setPage] = useState<Page>(Page.General);
  const [showSyncFailed, setShowSyncFailed] = useState(false);
  const [nowSyncing, setNowSyncing] = useState(false);
  const [
    showDisappearingTimerDialog,
    setShowDisappearingTimerDialog,
  ] = useState(false);

  useEffect(() => {
    document.body.classList.toggle('light-theme', theme === ThemeType.light);
    document.body.classList.toggle('dark-theme', theme === ThemeType.dark);
  }, [theme]);

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

  useEscapeHandling(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 onAudioOutputSelectChange = useCallback(
    (value: string) => {
      if (value === 'undefined') {
        onSelectedSpeakerChange(undefined);
      } else {
        onSelectedSpeakerChange(availableSpeakers[parseInt(value, 10)]);
      }
    },
    [onSelectedSpeakerChange, availableSpeakers]
  );

  let settings: JSX.Element | undefined;
  if (page === Page.General) {
    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('Preferences__button--general')}
          </div>
        </div>
        <SettingsRow>
          <Control left={i18n('Preferences--device-name')} right={deviceName} />
        </SettingsRow>
        <SettingsRow title={i18n('Preferences--system')}>
          {isAutoLaunchSupported && (
            <Checkbox
              checked={hasAutoLaunch}
              label={i18n('autoLaunchDescription')}
              moduleClassName="Preferences__checkbox"
              name="autoLaunch"
              onChange={onAutoLaunchChange}
            />
          )}
          {isHideMenuBarSupported && (
            <Checkbox
              checked={hasHideMenuBar}
              label={i18n('hideMenuBar')}
              moduleClassName="Preferences__checkbox"
              name="hideMenuBar"
              onChange={onHideMenuBarChange}
            />
          )}
          {isSystemTraySupported && (
            <>
              <Checkbox
                checked={hasMinimizeToSystemTray}
                label={i18n('SystemTraySetting__minimize-to-system-tray')}
                moduleClassName="Preferences__checkbox"
                name="system-tray-setting-minimize-to-system-tray"
                onChange={onMinimizeToSystemTrayChange}
              />
              <Checkbox
                checked={hasMinimizeToAndStartInSystemTray}
                disabled={!hasMinimizeToSystemTray}
                label={i18n(
                  '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('permissions')}>
          <Checkbox
            checked={hasMediaPermissions}
            label={i18n('mediaPermissionsDescription')}
            moduleClassName="Preferences__checkbox"
            name="mediaPermissions"
            onChange={onMediaPermissionsChange}
          />
          <Checkbox
            checked={hasMediaCameraPermissions}
            label={i18n('mediaCameraPermissionsDescription')}
            moduleClassName="Preferences__checkbox"
            name="mediaCameraPermissions"
            onChange={onMediaCameraPermissionsChange}
          />
        </SettingsRow>
        {isAutoDownloadUpdatesSupported && (
          <SettingsRow title={i18n('Preferences--updates')}>
            <Checkbox
              checked={hasAutoDownloadUpdate}
              label={i18n('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('Preferences__button--appearance')}
          </div>
        </div>
        <SettingsRow>
          <Control
            left={i18n('Preferences--theme')}
            right={
              <Select
                onChange={onThemeChange}
                options={[
                  {
                    text: i18n('themeSystem'),
                    value: 'system',
                  },
                  {
                    text: i18n('themeLight'),
                    value: 'light',
                  },
                  {
                    text: i18n('themeDark'),
                    value: 'dark',
                  },
                ]}
                value={themeSetting}
              />
            }
          />
          <Control
            left={i18n('showChatColorEditor')}
            onClick={() => {
              setPage(Page.ChatColor);
            }}
            right={
              <div
                className={`module-conversation-details__chat-color module-conversation-details__chat-color--${defaultConversationColor.color}`}
                style={{
                  ...getCustomColorStyle(
                    defaultConversationColor.customColorData?.value
                  ),
                }}
              />
            }
          />
          <Control
            left={i18n('Preferences--zoom')}
            right={
              <Select
                onChange={onZoomSelectChange}
                options={zoomFactors}
                value={zoomFactor}
              />
            }
          />
        </SettingsRow>
      </>
    );
  } else if (page === Page.Chats) {
    let spellCheckDirtyText: string | undefined;
    if (initialSpellCheckSetting !== hasSpellCheck) {
      spellCheckDirtyText = hasSpellCheck
        ? i18n('spellCheckWillBeEnabled')
        : i18n('spellCheckWillBeDisabled');
    }

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

    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('Preferences__button--chats')}
          </div>
        </div>
        <SettingsRow title={i18n('Preferences__button--chats')}>
          <Checkbox
            checked={hasSpellCheck}
            description={spellCheckDirtyText}
            label={i18n('spellCheckDescription')}
            moduleClassName="Preferences__checkbox"
            name="spellcheck"
            onChange={onSpellCheckChange}
          />
          <Checkbox
            checked={hasLinkPreviews}
            description={i18n('Preferences__link-previews--description')}
            disabled
            label={i18n('Preferences__link-previews--title')}
            moduleClassName="Preferences__checkbox"
            name="linkPreviews"
            onChange={noop}
          />
        </SettingsRow>
        {isSyncSupported && (
          <SettingsRow>
            <Control
              left={
                <>
                  <div>{i18n('sync')}</div>
                  <div className="Preferences__description">
                    {i18n('syncExplanation')}{' '}
                    {i18n('Preferences--lastSynced', {
                      date: lastSyncDate.toLocaleDateString(),
                      time: lastSyncDate.toLocaleTimeString(),
                    })}
                  </div>
                  {showSyncFailed && (
                    <div className="Preferences__description Preferences__description--error">
                      {i18n('syncFailed')}
                    </div>
                  )}
                </>
              }
              right={
                <div className="Preferences__right-button">
                  <Button
                    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('syncNow')}
                  </Button>
                </div>
              }
            />
          </SettingsRow>
        )}
      </>
    );
  } else if (page === Page.Calls) {
    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('Preferences__button--calls')}
          </div>
        </div>
        <SettingsRow title={i18n('calling')}>
          <Checkbox
            checked={hasIncomingCallNotifications}
            label={i18n('incomingCallNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="incomingCallNotification"
            onChange={onIncomingCallNotificationsChange}
          />
          <Checkbox
            checked={hasCallRingtoneNotification}
            label={i18n('callRingtoneNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="callRingtoneNotification"
            onChange={onCallRingtoneNotificationChange}
          />
        </SettingsRow>
        <SettingsRow title={i18n('Preferences__devices')}>
          <Control
            left={
              <>
                <label className="Preferences__select-title" htmlFor="video">
                  {i18n('callingDeviceSelection__label--video')}
                </label>
                <Select
                  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(
                              'callingDeviceSelection__select--no-device'
                            ),
                            value: 'undefined',
                          },
                        ]
                  }
                  value={selectedCamera}
                />
              </>
            }
            right={<div />}
          />
          <Control
            left={
              <>
                <label
                  className="Preferences__select-title"
                  htmlFor="audio-input"
                >
                  {i18n('callingDeviceSelection__label--audio-input')}
                </label>
                <Select
                  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(
                              'callingDeviceSelection__select--no-device'
                            ),
                            value: 'undefined',
                          },
                        ]
                  }
                  value={selectedMicrophone?.index}
                />
              </>
            }
            right={<div />}
          />
          <Control
            left={
              <>
                <label
                  className="Preferences__select-title"
                  htmlFor="audio-output"
                >
                  {i18n('callingDeviceSelection__label--audio-output')}
                </label>
                <Select
                  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(
                              'callingDeviceSelection__select--no-device'
                            ),
                            value: 'undefined',
                          },
                        ]
                  }
                  value={selectedSpeaker?.index}
                />
              </>
            }
            right={<div />}
          />
        </SettingsRow>
        <SettingsRow title={i18n('Preferences--advanced')}>
          <Checkbox
            checked={hasRelayCalls}
            description={i18n('alwaysRelayCallsDetail')}
            label={i18n('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('Preferences__button--notifications')}
          </div>
        </div>
        <SettingsRow>
          <Checkbox
            checked={hasNotifications}
            label={i18n('Preferences__enable-notifications')}
            moduleClassName="Preferences__checkbox"
            name="notifications"
            onChange={onNotificationsChange}
          />
          <Checkbox
            checked={hasCallNotifications}
            label={i18n('callSystemNotificationDescription')}
            moduleClassName="Preferences__checkbox"
            name="callSystemNotification"
            onChange={onCallNotificationsChange}
          />
          {isNotificationAttentionSupported && (
            <Checkbox
              checked={hasNotificationAttention}
              label={i18n('notificationDrawAttention')}
              moduleClassName="Preferences__checkbox"
              name="notificationDrawAttention"
              onChange={onNotificationAttentionChange}
            />
          )}
          {isAudioNotificationsSupported && (
            <Checkbox
              checked={hasAudioNotifications}
              label={i18n('audioNotificationDescription')}
              moduleClassName="Preferences__checkbox"
              name="audioNotification"
              onChange={onAudioNotificationsChange}
            />
          )}
          <Checkbox
            checked={hasCountMutedConversations}
            label={i18n('countMutedConversationsDescription')}
            moduleClassName="Preferences__checkbox"
            name="countMutedConversations"
            onChange={onCountMutedConversationsChange}
          />
        </SettingsRow>
        <SettingsRow>
          <Control
            left={i18n('Preferences--notification-content')}
            right={
              <Select
                disabled={!hasNotifications}
                onChange={onNotificationContentChange}
                options={[
                  {
                    text: i18n('nameAndMessage'),
                    value: 'message',
                  },
                  {
                    text: i18n('nameOnly'),
                    value: 'name',
                  },
                  {
                    text: i18n('noNameOrMessage'),
                    value: 'count',
                  },
                ]}
                value={notificationContent}
              />
            }
          />
        </SettingsRow>
      </>
    );
  } else if (page === Page.Privacy) {
    const isCustomDisappearingMessageValue = !DEFAULT_DURATIONS_SET.has(
      universalExpireTimer
    );

    settings = (
      <>
        <div className="Preferences__title">
          <div className="Preferences__title--header">
            {i18n('Preferences__button--privacy')}
          </div>
        </div>
        <SettingsRow>
          <Control
            left={i18n('Preferences--blocked')}
            right={
              blockedCount === 1
                ? i18n('Preferences--blocked-count-singular', [
                    String(blockedCount),
                  ])
                : i18n('Preferences--blocked-count-plural', [
                    String(blockedCount || 0),
                  ])
            }
          />
        </SettingsRow>
        {isPhoneNumberSharingSupported ? (
          <SettingsRow title={i18n('Preferences__who-can--title')}>
            <Control
              left={i18n('Preferences--see-me')}
              right={
                <Select
                  disabled
                  onChange={noop}
                  options={[
                    {
                      text: i18n('Preferences__who-can--everybody'),
                      value: PhoneNumberSharingMode.Everybody,
                    },
                    {
                      text: i18n('Preferences__who-can--contacts'),
                      value: PhoneNumberSharingMode.ContactsOnly,
                    },
                    {
                      text: i18n('Preferences__who-can--nobody'),
                      value: PhoneNumberSharingMode.Nobody,
                    },
                  ]}
                  value={whoCanSeeMe}
                />
              }
            />
            <Control
              left={i18n('Preferences--find-me')}
              right={
                <Select
                  disabled
                  onChange={noop}
                  options={[
                    {
                      text: i18n('Preferences__who-can--everybody'),
                      value: PhoneNumberDiscoverability.Discoverable,
                    },
                    {
                      text: i18n('Preferences__who-can--nobody'),
                      value: PhoneNumberDiscoverability.NotDiscoverable,
                    },
                  ]}
                  value={whoCanFindMe}
                />
              }
            />
            <div className="Preferences__padding">
              <div className="Preferences__description">
                {i18n('Preferences__privacy--description')}
              </div>
            </div>
          </SettingsRow>
        ) : null}
        <SettingsRow title={i18n('Preferences--messaging')}>
          <Checkbox
            checked={hasReadReceipts}
            disabled
            label={i18n('Preferences--read-receipts')}
            moduleClassName="Preferences__checkbox"
            name="readReceipts"
            onChange={noop}
          />
          <Checkbox
            checked={hasTypingIndicators}
            disabled
            label={i18n('Preferences--typing-indicators')}
            moduleClassName="Preferences__checkbox"
            name="typingIndicators"
            onChange={noop}
          />
          <div className="Preferences__padding">
            <div className="Preferences__description">
              {i18n('Preferences__privacy--description')}
            </div>
          </div>
        </SettingsRow>
        {showDisappearingTimerDialog && (
          <DisappearingTimeDialog
            i18n={i18n}
            initialValue={universalExpireTimer}
            onClose={() => setShowDisappearingTimerDialog(false)}
            onSubmit={onUniversalExpireTimerChange}
          />
        )}
        <SettingsRow title={i18n('disappearingMessages')}>
          <Control
            left={
              <>
                <div>
                  {i18n('settings__DisappearingMessages__timer__label')}
                </div>
                <div className="Preferences__description">
                  {i18n('settings__DisappearingMessages__footer')}
                </div>
              </>
            }
            right={
              <Select
                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
                      : -1,
                    text: isCustomDisappearingMessageValue
                      ? formatExpirationTimer(i18n, universalExpireTimer)
                      : i18n('selectedCustomDisappearingTimeOption'),
                  },
                ])}
                value={universalExpireTimer}
              />
            }
          />
        </SettingsRow>
        <SettingsRow>
          <Control
            left={
              <>
                <div>{i18n('clearDataHeader')}</div>
                <div className="Preferences__description">
                  {i18n('clearDataExplanation')}
                </div>
              </>
            }
            right={
              <div className="Preferences__right-button">
                <Button
                  onClick={() => setConfirmDelete(true)}
                  variant={ButtonVariant.SecondaryDestructive}
                >
                  {i18n('clearDataButton')}
                </Button>
              </div>
            }
          />
        </SettingsRow>
        {confirmDelete ? (
          <ConfirmationDialog
            actions={[
              {
                action: doDeleteAllData,
                style: 'negative',
                text: i18n('clearDataButton'),
              },
            ]}
            i18n={i18n}
            onClose={() => {
              setConfirmDelete(false);
            }}
            title={i18n('deleteAllDataHeader')}
          >
            {i18n('deleteAllDataBody')}
          </ConfirmationDialog>
        ) : null}
      </>
    );
  } else if (page === Page.ChatColor) {
    settings = (
      <>
        <div className="Preferences__title">
          <button
            aria-label={i18n('goBack')}
            className="Preferences__back-icon"
            onClick={() => setPage(Page.Appearance)}
            type="button"
          />
          <div className="Preferences__title--header">
            {i18n('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}
        />
      </>
    );
  }

  return (
    <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('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('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('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('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('Preferences__button--notifications')}
        </button>
        <button
          type="button"
          className={classNames({
            Preferences__button: true,
            'Preferences__button--privacy': true,
            'Preferences__button--selected': page === Page.Privacy,
          })}
          onClick={() => setPage(Page.Privacy)}
        >
          {i18n('Preferences__button--privacy')}
        </button>
      </div>
      <div className="Preferences__settings-pane">{settings}</div>
    </div>
  );
};

const SettingsRow = ({
  children,
  title,
}: {
  children: ReactNode;
  title?: string;
}): JSX.Element => {
  return (
    <div className="Preferences__settings-row">
      {title && <h3 className="Preferences__padding">{title}</h3>}
      {children}
    </div>
  );
};

const Control = ({
  left,
  onClick,
  right,
}: {
  left: ReactNode;
  onClick?: () => unknown;
  right: ReactNode;
}): JSX.Element => {
  const content = (
    <>
      <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>;
};

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