// Copyright (c) 2015-2016 Yuya Ochiai
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.

/* eslint-disable max-lines */

import 'renderer/css/settings.css';

import React from 'react';
import {FormCheck, Col, FormGroup, FormText, Container, Row, Button, FormControl, Modal} from 'react-bootstrap';
import type {IntlShape} from 'react-intl';
import {FormattedMessage, injectIntl} from 'react-intl';
import type {ActionMeta, MultiValue} from 'react-select';
import ReactSelect from 'react-select';

import {localeTranslations} from 'common/utils/constants';

import type {CombinedConfig, LocalConfiguration} from 'types/config';
import type {SaveQueueItem} from 'types/settings';
import type {DeepPartial} from 'types/utils';

import AutoSaveIndicator, {SavingState} from './AutoSaveIndicator';

const CONFIG_TYPE_UPDATES = 'updates';
const CONFIG_TYPE_APP_OPTIONS = 'appOptions';

type Props = {
    show: boolean;
    onClose: () => void;
    intl: IntlShape;
}

type State = DeepPartial<CombinedConfig> & {
    ready: boolean;
    maximized?: boolean;
    savingState: SavingStateItems;
    userOpenedDownloadDialog: boolean;
    allowSaveSpellCheckerURL: boolean;
    availableLanguages: Array<{label: string; value: string}>;
    availableSpellcheckerLanguages: Array<{label: string; value: string}>;
    canUpgrade?: boolean;
}

type SavingStateItems = {
    appOptions: SavingState;
    updates: SavingState;
}

class SettingsPage extends React.PureComponent<Props, State> {
    trayIconThemeRef: React.RefObject<HTMLDivElement>;
    downloadLocationRef: React.RefObject<HTMLInputElement>;
    showTrayIconRef: React.RefObject<HTMLInputElement>;
    autostartRef: React.RefObject<HTMLInputElement>;
    hideOnStartRef: React.RefObject<HTMLInputElement>;
    minimizeToTrayRef: React.RefObject<HTMLInputElement>;
    flashWindowRef: React.RefObject<HTMLInputElement>;
    bounceIconRef: React.RefObject<HTMLInputElement>;
    showUnreadBadgeRef: React.RefObject<HTMLInputElement>;
    useSpellCheckerRef: React.RefObject<HTMLInputElement>;
    spellCheckerURLRef: React.RefObject<HTMLInputElement>;
    enableHardwareAccelerationRef: React.RefObject<HTMLInputElement>;
    startInFullscreenRef: React.RefObject<HTMLInputElement>;
    autoCheckForUpdatesRef: React.RefObject<HTMLInputElement>;
    logLevelRef: React.RefObject<HTMLSelectElement>;
    appLanguageRef: React.RefObject<HTMLSelectElement>;

    saveQueue: SaveQueueItem[];

    selectedSpellCheckerLocales: Array<{label: string; value: string}>;

    savingIsDebounced: boolean;
    resetSaveStateIsDebounced: boolean;

    constructor(props: Props) {
        super(props);
        this.state = {
            ready: false,
            savingState: {
                appOptions: SavingState.SAVING_STATE_DONE,
                updates: SavingState.SAVING_STATE_DONE,
            },
            userOpenedDownloadDialog: false,
            allowSaveSpellCheckerURL: false,
            availableLanguages: [],
            availableSpellcheckerLanguages: [],
        };

        this.getConfig();
        this.trayIconThemeRef = React.createRef();
        this.downloadLocationRef = React.createRef();
        this.showTrayIconRef = React.createRef();
        this.autostartRef = React.createRef();
        this.hideOnStartRef = React.createRef();
        this.minimizeToTrayRef = React.createRef();
        this.flashWindowRef = React.createRef();
        this.bounceIconRef = React.createRef();
        this.showUnreadBadgeRef = React.createRef();
        this.useSpellCheckerRef = React.createRef();
        this.enableHardwareAccelerationRef = React.createRef();
        this.startInFullscreenRef = React.createRef();
        this.spellCheckerURLRef = React.createRef();
        this.autoCheckForUpdatesRef = React.createRef();
        this.logLevelRef = React.createRef();
        this.appLanguageRef = React.createRef();

        this.saveQueue = [];
        this.selectedSpellCheckerLocales = [];

        this.savingIsDebounced = false;
        this.resetSaveStateIsDebounced = false;
    }

    componentDidMount() {
        window.desktop.onReloadConfiguration(() => {
            this.updateSaveState();
            this.getConfig();
        });

        window.desktop.getAvailableSpellCheckerLanguages().then((languages: string[]) => {
            const availableSpellcheckerLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
            availableSpellcheckerLanguages.sort((a, b) => a.label.localeCompare(b.label));
            this.setState({availableSpellcheckerLanguages});
        });

        window.desktop.getAvailableLanguages().then((languages: string[]) => {
            const availableLanguages = languages.filter((language) => localeTranslations[language]).map((language) => ({label: localeTranslations[language], value: language}));
            availableLanguages.sort((a, b) => a.label.localeCompare(b.label));
            this.setState({availableLanguages});
        });
    }

    getConfig = () => {
        window.desktop.getLocalConfiguration().then((config) => {
            this.setState({ready: true, maximized: false, ...this.convertConfigDataToState(config as Partial<LocalConfiguration>, this.state) as Omit<State, 'ready'>});
        });
    };

    convertConfigDataToState = (configData: Partial<LocalConfiguration>, currentState: Partial<State> = {}) => {
        const newState = Object.assign({} as State, configData);
        newState.savingState = currentState.savingState || {
            appOptions: SavingState.SAVING_STATE_DONE,
            updates: SavingState.SAVING_STATE_DONE,
        };
        this.selectedSpellCheckerLocales = configData.spellCheckerLocales?.map((language: string) => ({label: localeTranslations[language] || language, value: language})) || [];
        return newState;
    };

    saveSetting = (configType: 'updates' | 'appOptions', {key, data}: {key: keyof CombinedConfig; data: CombinedConfig[keyof CombinedConfig]}) => {
        this.saveQueue.push({
            configType,
            key,
            data,
        });
        this.updateSaveState();
        this.processSaveQueue();
    };

    processSaveQueue = () => {
        if (this.savingIsDebounced) {
            return;
        }

        this.savingIsDebounced = true;
        setTimeout(() => {
            this.savingIsDebounced = false;
            window.desktop.updateConfiguration(this.saveQueue.splice(0, this.saveQueue.length));
        }, 500);
    };

    updateSaveState = () => {
        let queuedUpdateCounts = {
            [CONFIG_TYPE_UPDATES]: 0,
            [CONFIG_TYPE_APP_OPTIONS]: 0,
        };

        queuedUpdateCounts = this.saveQueue.reduce((updateCounts, {configType}) => {
            updateCounts[configType]++;
            return updateCounts;
        }, queuedUpdateCounts);

        const savingState = Object.assign({}, this.state.savingState);

        Object.entries(queuedUpdateCounts).forEach(([configType, count]) => {
            if (count > 0) {
                savingState[configType as keyof SavingStateItems] = SavingState.SAVING_STATE_SAVING;
            } else if (count === 0 && savingState[configType as keyof SavingStateItems] === SavingState.SAVING_STATE_SAVING) {
                savingState[configType as keyof SavingStateItems] = SavingState.SAVING_STATE_SAVED;
                this.resetSaveState(configType as keyof SavingStateItems);
            }
        });

        this.setState({savingState});
    };

    resetSaveState = (configType: keyof SavingStateItems) => {
        if (this.resetSaveStateIsDebounced) {
            return;
        }
        this.resetSaveStateIsDebounced = true;
        setTimeout(() => {
            this.resetSaveStateIsDebounced = false;
            if (this.state.savingState[configType] !== SavingState.SAVING_STATE_SAVING) {
                const savingState = Object.assign({}, this.state.savingState);
                savingState[configType] = SavingState.SAVING_STATE_DONE;
                this.setState({savingState});
            }
        }, 2000);
    };

    handleChangeShowTrayIcon = () => {
        const shouldShowTrayIcon = this.showTrayIconRef.current?.checked;
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showTrayIcon', data: shouldShowTrayIcon});
        this.setState({
            showTrayIcon: shouldShowTrayIcon,
        });

        if (window.process.platform === 'darwin' && !shouldShowTrayIcon) {
            this.setState({
                minimizeToTray: false,
            });
        }
    };

    handleChangeTrayIconTheme = (theme: string) => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'trayIconTheme', data: theme});
        this.setState({
            trayIconTheme: theme,
        });
    };

    handleChangeAutoStart = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'autostart', data: this.autostartRef.current?.checked});
        this.setState({
            autostart: this.autostartRef.current?.checked,
        });
    };

    handleChangeHideOnStart = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'hideOnStart', data: this.hideOnStartRef.current?.checked});
        this.setState({
            hideOnStart: this.hideOnStartRef.current?.checked,
        });
    };

    handleChangeMinimizeToTray = () => {
        const shouldMinimizeToTray = (process.platform === 'win32' || this.state.showTrayIcon) && this.minimizeToTrayRef.current?.checked;

        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'minimizeToTray', data: shouldMinimizeToTray});
        this.setState({
            minimizeToTray: shouldMinimizeToTray,
        });
    };

    handleFlashWindow = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
            key: 'notifications',
            data: {
                ...this.state.notifications,
                flashWindow: this.flashWindowRef.current?.checked ? 2 : 0,
            } as CombinedConfig['notifications'],
        });
        this.setState({
            notifications: {
                ...this.state.notifications,
                flashWindow: this.flashWindowRef.current?.checked ? 2 : 0,
            },
        });
    };

    handleBounceIcon = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
            key: 'notifications',
            data: {
                ...this.state.notifications,
                bounceIcon: this.bounceIconRef.current?.checked,
            } as CombinedConfig['notifications'],
        });
        this.setState({
            notifications: {
                ...this.state.notifications,
                bounceIcon: this.bounceIconRef.current?.checked,
            },
        });
    };

    handleBounceIconType = (event: React.ChangeEvent<HTMLInputElement>) => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {
            key: 'notifications',
            data: {
                ...this.state.notifications,
                bounceIconType: event.target.value,
            } as CombinedConfig['notifications'],
        });
        this.setState({
            notifications: {
                ...this.state.notifications,
                bounceIconType: event.target.value as 'critical' | 'informational',
            },
        });
    };

    handleShowUnreadBadge = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'showUnreadBadge', data: this.showUnreadBadgeRef.current?.checked});
        this.setState({
            showUnreadBadge: this.showUnreadBadgeRef.current?.checked,
        });
    };

    handleChangeUseSpellChecker = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'useSpellChecker', data: this.useSpellCheckerRef.current?.checked});
        this.setState({
            useSpellChecker: this.useSpellCheckerRef.current?.checked,
        });
    };

    handleChangeLogLevel = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'logLevel', data: this.logLevelRef.current?.value});
        this.setState({
            logLevel: this.logLevelRef.current?.value,
        });
    };

    handleChangeAppLanguage = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'appLanguage', data: this.appLanguageRef.current?.value});
        this.setState({
            appLanguage: this.appLanguageRef.current?.value,
        });
    };

    handleChangeAutoCheckForUpdates = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_UPDATES, {key: 'autoCheckForUpdates', data: this.autoCheckForUpdatesRef.current?.checked});
        this.setState({
            autoCheckForUpdates: this.autoCheckForUpdatesRef.current?.checked,
        }, () => {
            if (this.state.autoCheckForUpdates) {
                this.checkForUpdates();
            }
        });
    };

    checkForUpdates = () => {
        window.desktop.checkForUpdates();
    };

    handleChangeSpellCheckerLocales = (value: MultiValue<{label: string; value: string}>, actionMeta: ActionMeta<{label: string; value: string}>) => {
        switch (actionMeta.action) {
        case 'select-option':
            this.selectedSpellCheckerLocales = [...value];
            break;
        case 'remove-value':
            this.selectedSpellCheckerLocales = this.selectedSpellCheckerLocales.filter((language) => language.value !== actionMeta.removedValue.value);
        }

        const values = this.selectedSpellCheckerLocales.map((language) => language.value);
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerLocales', data: values});
        this.setState({
            spellCheckerLocales: values,
        });
    };

    handleChangeEnableHardwareAcceleration = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'enableHardwareAcceleration', data: this.enableHardwareAccelerationRef.current?.checked});
        this.setState({
            enableHardwareAcceleration: this.enableHardwareAccelerationRef.current?.checked,
        });
    };

    handleChangeStartInFullscreen = () => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'startInFullscreen', data: this.startInFullscreenRef.current?.checked});
        this.setState({
            startInFullscreen: this.startInFullscreenRef.current?.checked,
        });
    };

    saveDownloadLocation = (location: string) => {
        if (!location) {
            return;
        }
        this.setState({
            downloadLocation: location,
        });
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'downloadLocation', data: location});
    };

    handleChangeDownloadLocation = (e: React.ChangeEvent<HTMLInputElement>) => {
        this.saveDownloadLocation(e.target.value);
    };

    selectDownloadLocation = () => {
        if (!this.state.userOpenedDownloadDialog) {
            window.desktop.getDownloadLocation(this.state.downloadLocation).then((result) => this.saveDownloadLocation(result));
            this.setState({userOpenedDownloadDialog: true});
        }
        this.setState({userOpenedDownloadDialog: false});
    };

    saveSpellCheckerURL = (): void => {
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: this.state.spellCheckerURL});
    };

    resetSpellCheckerURL = (): void => {
        this.setState({spellCheckerURL: undefined, allowSaveSpellCheckerURL: false});
        window.timers.setImmediate(this.saveSetting, CONFIG_TYPE_APP_OPTIONS, {key: 'spellCheckerURL', data: undefined});
    };

    handleChangeSpellCheckerURL = (e: React.ChangeEvent<HTMLInputElement>): void => {
        const dictionaryURL = e.target.value;
        let allowSaveSpellCheckerURL;
        try {
            // eslint-disable-next-line no-new
            new URL(dictionaryURL);
            allowSaveSpellCheckerURL = true;
        } catch {
            allowSaveSpellCheckerURL = false;
        }
        this.setState({
            spellCheckerURL: dictionaryURL,
            allowSaveSpellCheckerURL,
        });
    };

    handleDoubleClick = () => {
        window.desktop.doubleClickOnWindow('settings');
    };

    render() {
        const {intl} = this.props;

        const settingsPage = {
            close: {
                textDecoration: 'none',
                position: 'absolute',
                right: '0',
                top: '5px',
                fontSize: '35px',
                fontWeight: 'normal',
                color: '#bbb',
            },
            heading: {
                textAlign: 'center' as const,
                fontSize: '24px',
                margin: '0',
                padding: '1em 0',
            },
            sectionHeading: {
                fontSize: '20px',
                margin: '0',
                padding: '1em 0',
                display: 'inline-block',
            },
            sectionHeadingLink: {
                marginTop: '24px',
                display: 'inline-block',
                fontSize: '15px',
            },
            footer: {
                padding: '0.4em 0',
            },
            downloadLocationInput: {
                marginRight: '3px',
                marginTop: '8px',
                width: '320px',
                height: '34px',
                padding: '0 12px',
                borderRadius: '4px',
                border: '1px solid #ccc',
                fontWeight: 500,
            },

            downloadLocationButton: {
                marginBottom: '4px',
            },

            logLevelInput: {
                marginRight: '3px',
                marginTop: '8px',
                width: '320px',
                height: '34px',
                padding: '0 12px',
                borderRadius: '4px',
                border: '1px solid #ccc',
                fontWeight: 500,
            },

            appLanguageInput: {
                marginRight: '3px',
                marginTop: '8px',
                width: '320px',
                height: '34px',
                padding: '0 12px',
                borderRadius: '4px',
                border: '1px solid #ccc',
                fontWeight: 500,
            },

            container: {
                paddingBottom: '40px',
            },

            checkForUpdatesButton: {
                marginBottom: '4px',
                marginLeft: '16px',
                marginTop: '8px',
            },
        };

        const options = [];

        // MacOS has an option in the Dock, to set the app to autostart, so we choose to not support this option for OSX
        if (window.process.platform === 'win32' || window.process.platform === 'linux') {
            options.push(
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='inputAutoStart'
                        id='inputAutoStart'
                        ref={this.autostartRef}
                        checked={this.state.autostart}
                        onChange={this.handleChangeAutoStart}
                    />
                    <FormattedMessage
                        id='renderer.components.settingsPage.startAppOnLogin'
                        defaultMessage='Start app on login'
                    />
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.startAppOnLogin.description'
                            defaultMessage='If enabled, the app starts automatically when you log in to your machine.'
                        />
                    </FormText>
                </FormCheck>);

            options.push(
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='inputHideOnStart'
                        id='inputHideOnStart'
                        ref={this.hideOnStartRef}
                        checked={this.state.hideOnStart}
                        onChange={this.handleChangeHideOnStart}
                    />
                    <FormattedMessage
                        id='renderer.components.settingsPage.launchAppMinimized'
                        defaultMessage='Launch app minimized'
                    />
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.launchAppMinimized.description'
                            defaultMessage='If enabled, the app will start in system tray, and will not show the window on launch.'
                        />
                    </FormText>
                </FormCheck>);
        }

        options.push(
            <>
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='inputSpellChecker'
                        id='inputSpellChecker'
                        ref={this.useSpellCheckerRef}
                        checked={this.state.useSpellChecker}
                        onChange={this.handleChangeUseSpellChecker}
                    />
                    <FormattedMessage
                        id='renderer.components.settingsPage.checkSpelling'
                        defaultMessage='Check spelling'
                    />
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.checkSpelling.description'
                            defaultMessage='Highlight misspelled words in your messages based on your system language or language preference.'
                        />
                        {' '}
                        <FormattedMessage
                            id='renderer.components.settingsPage.afterRestart'
                            defaultMessage='Setting takes effect after restarting the app.'
                        />
                    </FormText>
                </FormCheck>
                {this.state.useSpellChecker &&
                    <ReactSelect
                        inputId='inputSpellCheckerLocalesDropdown'
                        className='SettingsPage__spellCheckerLocalesDropdown'
                        classNamePrefix='SettingsPage__spellCheckerLocalesDropdown'
                        options={this.state.availableSpellcheckerLanguages}
                        isMulti={true}
                        isClearable={false}
                        onChange={this.handleChangeSpellCheckerLocales}
                        value={this.selectedSpellCheckerLocales}
                        placeholder={
                            <FormattedMessage
                                id='renderer.components.settingsPage.checkSpelling.preferredLanguages'
                                defaultMessage='Select preferred language(s)'
                            />
                        }
                    />
                }
            </>,
        );
        if (process.platform !== 'darwin') {
            if (this.state.spellCheckerURL === null || typeof this.state.spellCheckerURL === 'undefined') {
                options.push(
                    <Button
                        id='editSpellcheckerURL'
                        key='editSpellcheckerURL'
                        onClick={() => this.setState({spellCheckerURL: '', allowSaveSpellCheckerURL: false})}
                        variant='link'
                    >
                        <FormattedMessage
                            id='renderer.components.settingsPage.checkSpelling.editSpellcheckUrl'
                            defaultMessage='Use an alternative dictionary URL'
                        />
                    </Button>,
                );
            } else {
                options.push(
                    <div
                        style={settingsPage.container}
                        key='containerInputSpellcheckerURL'
                    >
                        <input
                            disabled={!this.state.useSpellChecker}
                            style={settingsPage.downloadLocationInput}
                            key='inputSpellCheckerURL'
                            id='inputSpellCheckerURL'
                            ref={this.spellCheckerURLRef}
                            onChange={this.handleChangeSpellCheckerURL}
                            value={this.state.spellCheckerURL}
                        />
                        <Button
                            disabled={!this.state.allowSaveSpellCheckerURL}
                            key='saveSpellCheckerURL'
                            style={settingsPage.downloadLocationButton}
                            id='saveSpellCheckerURL'
                            onClick={this.saveSpellCheckerURL}
                        >
                            <FormattedMessage
                                id='label.save'
                                defaultMessage='Save'
                            />
                        </Button>
                        <FormText>
                            <FormattedMessage
                                id='renderer.components.settingsPage.checkSpelling.specifyURL'
                                defaultMessage='Specify the url where dictionary definitions can be retrieved'
                            />
                        </FormText>
                        <Button
                            id='revertSpellcheckerURL'
                            key='revertSpellcheckerURL'
                            onClick={this.resetSpellCheckerURL}
                            variant='link'
                        >
                            <FormattedMessage
                                id='renderer.components.settingsPage.checkSpelling.revertToDefault'
                                defaultMessage='Revert to default'
                            />
                        </Button>
                    </div>);
            }
        }
        if (window.process.platform === 'darwin' || window.process.platform === 'win32') {
            const taskbar = window.process.platform === 'win32' ? 'taskbar' : 'Dock';
            options.push(
                <FormCheck
                    key='showunreadbadge'
                >
                    <FormCheck.Input
                        type='checkbox'
                        key='inputShowUnreadBadge'
                        id='inputShowUnreadBadge'
                        ref={this.showUnreadBadgeRef}
                        checked={this.state.showUnreadBadge}
                        onChange={this.handleShowUnreadBadge}
                    />
                    <FormattedMessage
                        id='renderer.components.settingsPage.showUnreadBadge'
                        defaultMessage='Show red badge on {taskbar} icon to indicate unread messages'
                        values={{taskbar}}
                    />
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.showUnreadBadge.description'
                            defaultMessage='Regardless of this setting, mentions are always indicated with a red badge and item count on the {taskbar} icon.'
                            values={{taskbar}}
                        />
                    </FormText>
                </FormCheck>);
        }

        if (window.process.platform === 'win32' || window.process.platform === 'linux') {
            options.push(
                <FormCheck>
                    <FormCheck.Input
                        type='checkbox'
                        key='flashWindow'
                        id='inputflashWindow'
                        ref={this.flashWindowRef}
                        checked={!this.state.notifications || this.state.notifications.flashWindow === 2}
                        onChange={this.handleFlashWindow}
                    />
                    <FormattedMessage
                        id='renderer.components.settingsPage.flashWindow'
                        defaultMessage='Flash taskbar icon when a new message is received'
                    />
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.flashWindow.description'
                            defaultMessage='If enabled, the taskbar icon will flash for a few seconds when a new message is received.'
                        />
                        {window.process.platform === 'linux' && (
                            <>
                                <br/>
                                <em>
                                    <strong>
                                        <FormattedMessage
                                            id='renderer.components.settingsPage.flashWindow.description.note'
                                            defaultMessage='NOTE: '
                                        />
                                    </strong>
                                    <FormattedMessage
                                        id='renderer.components.settingsPage.flashWindow.description.linuxFunctionality'
                                        defaultMessage='This functionality may not work with all Linux window managers.'
                                    />
                                </em>
                            </>
                        )}
                    </FormText>
                </FormCheck>);
        }

        if (window.process.platform === 'darwin') {
            options.push(
                <FormGroup
                    key='OptionsForm'
                >
                    <FormCheck
                        type='checkbox'
                        inline={true}
                        key='bounceIcon'
                        id='inputBounceIcon'
                        ref={this.bounceIconRef}
                        checked={this.state.notifications ? this.state.notifications.bounceIcon : false}
                        onChange={this.handleBounceIcon}
                        style={{marginRight: '10px'}}
                        label={
                            <FormattedMessage
                                id='renderer.components.settingsPage.bounceIcon'
                                defaultMessage='Bounce the Dock icon'
                            />
                        }
                    />
                    <FormCheck
                        type='radio'
                        inline={true}
                        name='bounceIconType'
                        value='informational'
                        disabled={!this.state.notifications || !this.state.notifications.bounceIcon}
                        defaultChecked={
                            !this.state.notifications ||
                !this.state.notifications.bounceIconType ||
                this.state.notifications.bounceIconType === 'informational'
                        }
                        onChange={this.handleBounceIconType}
                        label={
                            <FormattedMessage
                                id='renderer.components.settingsPage.bounceIcon.once'
                                defaultMessage='once'
                            />
                        }
                    />
                    {' '}
                    <FormCheck
                        type='radio'
                        inline={true}
                        name='bounceIconType'
                        value='critical'
                        disabled={!this.state.notifications || !this.state.notifications.bounceIcon}
                        defaultChecked={this.state.notifications && this.state.notifications.bounceIconType === 'critical'}
                        onChange={this.handleBounceIconType}
                        label={
                            <FormattedMessage
                                id='renderer.components.settingsPage.bounceIcon.untilOpenApp'
                                defaultMessage='until I open the app'
                            />
                        }
                    />
                    <FormText
                        style={{marginLeft: '20px'}}
                    >
                        <FormattedMessage
                            id='renderer.components.settingsPage.bounceIcon.description'
                            defaultMessage='If enabled, the Dock icon bounces once or until the user opens the app when a new notification is received.'
                        />
                    </FormText>
                </FormGroup>,
            );
        }

        if (window.process.platform === 'darwin' || window.process.platform === 'linux') {
            options.push(
                <FormCheck
                    key='inputShowTrayIcon'
                >
                    <FormCheck.Input
                        type='checkbox'
                        id='inputShowTrayIcon'
                        ref={this.showTrayIconRef}
                        checked={this.state.showTrayIcon}
                        onChange={this.handleChangeShowTrayIcon}
                    />
                    {window.process.platform === 'darwin' ?
                        <FormattedMessage
                            id='renderer.components.settingsPage.trayIcon.show.darwin'
                            defaultMessage='Show {appName} icon in the menu bar'
                            values={{appName: this.state.appName}}
                        /> :
                        <FormattedMessage
                            id='renderer.components.settingsPage.trayIcon.show'
                            defaultMessage='Show icon in the notification area'
                        />
                    }
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.afterRestart'
                            defaultMessage='Setting takes effect after restarting the app.'
                        />
                    </FormText>
                </FormCheck>);
        }

        if (this.state.showTrayIcon) {
            if (window.process.platform === 'linux' || window.process.platform === 'win32') {
                options.push(
                    <FormGroup
                        key='trayIconTheme'
                        ref={this.trayIconThemeRef}
                        style={{marginLeft: '20px'}}
                    >
                        <FormattedMessage
                            id='renderer.components.settingsPage.trayIcon.color'
                            defaultMessage='Icon color: '
                        />
                        {window.process.platform === 'win32' &&
                            <>
                                <FormCheck
                                    type='radio'
                                    inline={true}
                                    name='trayIconTheme'
                                    value='use_system'
                                    defaultChecked={this.state.trayIconTheme === 'use_system' || !this.state.trayIconTheme}
                                    onChange={() => this.handleChangeTrayIconTheme('use_system')}
                                    label={
                                        <FormattedMessage
                                            id='renderer.components.settingsPage.trayIcon.theme.systemDefault'
                                            defaultMessage='Use system default'
                                        />
                                    }
                                />
                                {' '}
                            </>
                        }
                        <FormCheck
                            type='radio'
                            inline={true}
                            name='trayIconTheme'
                            value='light'
                            defaultChecked={this.state.trayIconTheme === 'light' || !this.state.trayIconTheme}
                            onChange={() => this.handleChangeTrayIconTheme('light')}
                            label={
                                <FormattedMessage
                                    id='renderer.components.settingsPage.trayIcon.theme.light'
                                    defaultMessage='Light'
                                />
                            }
                        />
                        {' '}
                        <FormCheck
                            type='radio'
                            inline={true}
                            name='trayIconTheme'
                            value='dark'
                            defaultChecked={this.state.trayIconTheme === 'dark'}
                            onChange={() => this.handleChangeTrayIconTheme('dark')}
                            label={
                                <FormattedMessage
                                    id='renderer.components.settingsPage.trayIcon.theme.dark'
                                    defaultMessage='Dark'
                                />
                            }
                        />
                    </FormGroup>,
                );
            }
        }

        if (window.process.platform === 'linux' || window.process.platform === 'win32') {
            options.push(
                <FormCheck
                    key='inputMinimizeToTray'
                >
                    <FormCheck.Input
                        type='checkbox'
                        id='inputMinimizeToTray'
                        ref={this.minimizeToTrayRef}
                        disabled={process.platform !== 'win32' && !this.state.showTrayIcon}
                        checked={this.state.minimizeToTray}
                        onChange={this.handleChangeMinimizeToTray}
                    />
                    <FormattedMessage
                        id='renderer.components.settingsPage.minimizeToTray'
                        defaultMessage='Leave app running in notification area when application window is closed'
                    />
                    <FormText>
                        <FormattedMessage
                            id='renderer.components.settingsPage.minimizeToTray.description'
                            defaultMessage='If enabled, the app stays running in the notification area after app window is closed.'
                        />
                        {this.state.showTrayIcon &&
                            <>
                                {' '}
                                <FormattedMessage
                                    id='renderer.components.settingsPage.afterRestart'
                                    defaultMessage='Setting takes effect after restarting the app.'
                                />
                            </>
                        }
                    </FormText>
                </FormCheck>);
        }

        options.push(
            <FormCheck
                key='inputEnableHardwareAcceleration'
            >
                <FormCheck.Input
                    type='checkbox'
                    id='inputEnableHardwareAcceleration'
                    ref={this.enableHardwareAccelerationRef}
                    checked={this.state.enableHardwareAcceleration}
                    onChange={this.handleChangeEnableHardwareAcceleration}
                />
                <FormattedMessage
                    id='renderer.components.settingsPage.enableHardwareAcceleration'
                    defaultMessage='Use GPU hardware acceleration'
                />
                <FormText>
                    <FormattedMessage
                        id='renderer.components.settingsPage.enableHardwareAcceleration.description'
                        defaultMessage='If enabled, {appName} UI is rendered more efficiently but can lead to decreased stability for some systems.'
                        values={{
                            appName: this.state.appName,
                        }}
                    />
                    {' '}
                    <FormattedMessage
                        id='renderer.components.settingsPage.afterRestart'
                        defaultMessage='Setting takes effect after restarting the app.'
                    />
                </FormText>
            </FormCheck>,
        );

        options.push(
            <FormCheck
                key='inputStartInFullScreen'
            >
                <FormCheck.Input
                    type='checkbox'
                    id='inputStartInFullScreen'
                    ref={this.startInFullscreenRef}
                    checked={this.state.startInFullscreen}
                    onChange={this.handleChangeStartInFullscreen}
                />
                <FormattedMessage
                    id='renderer.components.settingsPage.fullscreen'
                    defaultMessage='Open app in fullscreen'
                />
                <FormText>
                    <FormattedMessage
                        id='renderer.components.settingsPage.fullscreen.description'
                        defaultMessage='If enabled, the {appName} application will always open in full screen'
                        values={{
                            appName: this.state.appName,
                        }}
                    />
                </FormText>
            </FormCheck>,
        );

        options.push(
            <div
                style={settingsPage.container}
                key='containerDownloadLocation'
            >
                <hr/>
                <FormattedMessage
                    id='renderer.components.settingsPage.appLanguage'
                    defaultMessage='Set app language (beta)'
                />
                <FormControl
                    style={settingsPage.appLanguageInput}
                    as='select'
                    id='inputAppLanguage'
                    ref={this.appLanguageRef}
                    value={this.state.appLanguage}
                    onChange={this.handleChangeAppLanguage}
                >
                    <option value=''>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.appLanguage.useSystemDefault', defaultMessage: 'Use system default'})}
                    </option>
                    {this.state.availableLanguages.map((language) => {
                        return (
                            <option
                                key={language.value}
                                value={language.value}
                            >
                                {language.label}
                            </option>
                        );
                    })}
                </FormControl>
                <FormText>
                    <FormattedMessage
                        id='renderer.components.settingsPage.appLanguage.description'
                        defaultMessage='Chooses the language that the Desktop App will use for menu items and popups. Still in beta, some languages will be missing translation strings.'
                    />
                    <br/>
                    <FormattedMessage
                        id='renderer.components.settingsPage.afterRestart'
                        defaultMessage='Setting takes effect after restarting the app.'
                    />
                </FormText>
                <br/>
                <div>
                    <FormattedMessage
                        id='renderer.components.settingsPage.downloadLocation'
                        defaultMessage='Download Location'
                    />
                </div>
                <input
                    disabled={true}
                    style={settingsPage.downloadLocationInput}
                    key='inputDownloadLocation'
                    id='inputDownloadLocation'
                    ref={this.downloadLocationRef}
                    onChange={this.handleChangeDownloadLocation}
                    value={this.state.downloadLocation}
                />
                <Button
                    style={settingsPage.downloadLocationButton}
                    id='saveDownloadLocation'
                    onClick={this.selectDownloadLocation}
                >
                    <FormattedMessage
                        id='label.change'
                        defaultMessage='Change'
                    />
                </Button>
                <FormText>
                    <FormattedMessage
                        id='renderer.components.settingsPage.downloadLocation.description'
                        defaultMessage='Specify the folder where files will download.'
                    />
                </FormText>
                <br/>
                <FormattedMessage
                    id='renderer.components.settingsPage.loggingLevel'
                    defaultMessage='Logging level'
                />
                <FormControl
                    style={settingsPage.logLevelInput}
                    as='select'
                    id='inputLogLevel'
                    ref={this.logLevelRef}
                    value={this.state.logLevel}
                    onChange={this.handleChangeLogLevel}
                >
                    <option value='error'>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.loggingLevel.level.error', defaultMessage: 'Errors (error)'})}
                    </option>
                    <option value='warn'>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.loggingLevel.level.warn', defaultMessage: 'Errors and Warnings (warn)'})}
                    </option>
                    <option value='info'>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.loggingLevel.level.info', defaultMessage: 'Info (info)'})}
                    </option>
                    <option value='verbose'>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.loggingLevel.level.verbose', defaultMessage: 'Verbose (verbose)'})}
                    </option>
                    <option value='debug'>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.loggingLevel.level.debug', defaultMessage: 'Debug (debug)'})}
                    </option>
                    <option value='silly'>
                        {intl.formatMessage({id: 'renderer.components.settingsPage.loggingLevel.level.silly', defaultMessage: 'Finest (silly)'})}
                    </option>
                </FormControl>
                <FormText>
                    <FormattedMessage
                        id='renderer.components.settingsPage.loggingLevel.description'
                        defaultMessage='Logging is helpful for developers and support to isolate issues you may be encountering with the desktop app.'
                    />
                    <br/>
                    <FormattedMessage
                        id='renderer.components.settingsPage.loggingLevel.description.subtitle'
                        defaultMessage='Increasing the log level increases disk space usage and can impact performance. We recommend only increasing the log level if you are having issues.'
                    />
                </FormText>
            </div>,
        );

        let optionsRow = null;
        if (options.length > 0) {
            optionsRow = (
                <Row>
                    <Col md={12}>
                        <h2 style={settingsPage.sectionHeading}>
                            <FormattedMessage
                                id='renderer.components.settingsPage.appOptions'
                                defaultMessage='App Options'
                            />
                        </h2>
                        <div className='IndicatorContainer appOptionsSaveIndicator'>
                            <AutoSaveIndicator
                                id='appOptionsSaveIndicator'
                                savingState={this.state.savingState.appOptions}
                                errorMessage={
                                    <FormattedMessage
                                        id='renderer.components.settingsPage.saving.error'
                                        defaultMessage={'Can\'t save your changes. Please try again.'}
                                    />
                                }
                            />
                        </div>
                        { options.map((opt) => (
                            <FormGroup key={opt.key}>
                                {opt}
                            </FormGroup>
                        )) }
                    </Col>
                </Row>
            );
        }

        let updateRow = null;
        if (this.state.canUpgrade) {
            updateRow = (
                <>
                    <Row>
                        <Col md={12}>
                            <h2 style={settingsPage.sectionHeading}>
                                <FormattedMessage
                                    id='renderer.components.settingsPage.updates'
                                    defaultMessage='Updates'
                                />
                            </h2>
                            <div className='IndicatorContainer updatesSaveIndicator'>
                                <AutoSaveIndicator
                                    id='updatesSaveIndicator'
                                    savingState={this.state.savingState.updates}
                                    errorMessage={
                                        <FormattedMessage
                                            id='renderer.components.settingsPage.saving.error'
                                            defaultMessage={'Can\'t save your changes. Please try again.'}
                                        />
                                    }
                                />
                            </div>
                            <FormGroup
                                key='inputAutoCheckForUpdates'
                            >
                                <FormCheck>
                                    <FormCheck.Input
                                        type='checkbox'
                                        key='inputAutoCheckForUpdates'
                                        id='inputAutoCheckForUpdates'
                                        ref={this.autoCheckForUpdatesRef}
                                        checked={this.state.autoCheckForUpdates}
                                        onChange={this.handleChangeAutoCheckForUpdates}
                                    />
                                    <FormattedMessage
                                        id='renderer.components.settingsPage.updates.automatic'
                                        defaultMessage='Automatically check for updates'
                                    />
                                    <FormText>
                                        <FormattedMessage
                                            id='renderer.components.settingsPage.updates.automatic.description'
                                            defaultMessage='If enabled, updates to the Desktop App will download automatically and you will be notified when ready to install.'
                                        />
                                    </FormText>
                                </FormCheck>
                                <Button
                                    style={settingsPage.checkForUpdatesButton}
                                    id='checkForUpdatesNow'
                                    onClick={this.checkForUpdates}
                                >
                                    <FormattedMessage
                                        id='renderer.components.settingsPage.updates.checkNow'
                                        defaultMessage='Check for Updates Now'
                                    />
                                </Button>
                            </FormGroup>
                        </Col>
                    </Row>
                    <hr/>
                </>
            );
        }

        let waitForIpc;
        if (this.state.ready) {
            waitForIpc = (
                <>
                    {updateRow}
                    {optionsRow}
                </>
            );
        } else {
            waitForIpc = (
                <p>
                    <FormattedMessage
                        id='renderer.components.settingsPage.loadingConfig'
                        defaultMessage='Loading configuration...'
                    />
                </p>
            );
        }

        return (
            <Modal
                show={this.props.show}
                id='settingsModal'
                onHide={this.props.onClose}
            >
                <Modal.Header closeButton={true}>
                    <Modal.Title>
                        <FormattedMessage
                            id='renderer.components.settingsPage.header'
                            defaultMessage='Settings'
                        />
                    </Modal.Title>
                </Modal.Header>

                <Modal.Body>
                    <div
                        style={{
                            overflowY: 'auto',
                            height: '100%',
                            margin: '0 -15px',
                        }}
                    >
                        <Container
                            className='settingsPage'
                        >
                            {waitForIpc}
                        </Container>
                    </div>
                </Modal.Body>
            </Modal>
        );
    }
}

export default injectIntl(SettingsPage);
