/* eslint-disable lines-around-comment */

import React from 'react';
import { WithTranslation } from 'react-i18next';
import { Animated, Text, View } from 'react-native';

import { translate } from '../../../base/i18n/functions';
import {
    Icon,
    IconCloseLarge,
    IconInfoCircle,
    IconUsers,
    IconWarning
    // @ts-ignore
} from '../../../base/icons';
import { colors } from '../../../base/ui/Tokens';
import BaseTheme from '../../../base/ui/components/BaseTheme.native';
import Button from '../../../base/ui/components/native/Button';
import IconButton from '../../../base/ui/components/native/IconButton';
import { BUTTON_MODES, BUTTON_TYPES } from '../../../base/ui/constants.native';
import { replaceNonUnicodeEmojis } from '../../../chat/functions';
import { NOTIFICATION_ICON } from '../../constants';
import AbstractNotification, {
    type Props as AbstractNotificationProps
    // @ts-ignore
} from '../AbstractNotification';

// @ts-ignore
import styles from './styles';


/**
 * Secondary colors for notification icons.
 *
 * @type {{error, info, normal, success, warning}}
 */

const ICON_COLOR = {
    error: colors.error06,
    normal: colors.primary06,
    success: colors.success05,
    warning: colors.warning05
};


export type Props = AbstractNotificationProps & WithTranslation & {
    _participants: ArrayLike<any>;
};


/**
 * Implements a React {@link Component} to display a notification.
 *
 * @augments Component
 */
class Notification extends AbstractNotification<Props> {

    /**
     * Initializes a new {@code Notification} instance.
     *
     * @inheritdoc
     */
    constructor(props: Props) {
        super(props);

        // @ts-ignore
        this.state = {
            notificationContainerAnimation: new Animated.Value(0)
        };
    }

    /**
     * Implements React's {@link Component#componentDidMount()}.
     *
     * @inheritdoc
     */
    componentDidMount() {
        Animated.timing(
            // @ts-ignore
            this.state.notificationContainerAnimation,
            {
                toValue: 1,
                duration: 500,
                useNativeDriver: true
            })
            .start();
    }

    /**
     * Creates action button configurations for the notification based on
     * notification appearance.
     *
     * @private
     * @returns {Object[]}
     */
    _mapAppearanceToButtons() {
        const {
            customActionHandler,
            customActionNameKey,
            customActionType
            // @ts-ignore
        } = this.props;

        if (customActionNameKey?.length && customActionHandler?.length && customActionType?.length) {
            return customActionNameKey?.map((customAction: string, index: number) => (
                <Button
                    accessibilityLabel = { customAction }
                    key = { index }
                    labelKey = { customAction }
                    mode = { BUTTON_MODES.TEXT }
                    // eslint-disable-next-line react/jsx-no-bind
                    onClick = { () => {
                        if (customActionHandler[index]()) {
                            this._onDismissed();
                        }
                    } }
                    style = { styles.btn }
                    type = { customActionType[index] } />
            ));
        }

        return [];
    }

    /**
     * Returns the Icon type component to be used, based on icon or appearance.
     *
     * @returns {ReactElement}
     */
    _getIcon() {
        const {
            appearance,
            icon
            // @ts-ignore
        } = this.props;

        let src;

        switch (icon || appearance) {
        case NOTIFICATION_ICON.PARTICIPANT:
            src = IconInfoCircle;
            break;
        case NOTIFICATION_ICON.PARTICIPANTS:
            src = IconUsers;
            break;
        case NOTIFICATION_ICON.WARNING:
            src = IconWarning;
            break;
        default:
            src = IconInfoCircle;
            break;
        }

        return src;
    }

    /**
     * Creates an icon component depending on the configured notification
     * appearance.
     *
     * @private
     * @returns {ReactElement}
     */
    _mapAppearanceToIcon() {
        // @ts-ignore
        const { appearance } = this.props;
        // @ts-ignore
        const color = ICON_COLOR[appearance];

        return (
            <View style = { styles.iconContainer }>
                <Icon
                    color = { color }
                    size = { 24 }
                    src = { this._getIcon() } />
            </View>
        );
    }

    /**
     * Implements React's {@link Component#render()}.
     *
     * @inheritdoc
     * @returns {ReactElement}
     */
    render() {
        // @ts-ignore
        const { icon } = this.props;
        const contentColumnStyles = icon === NOTIFICATION_ICON.PARTICIPANTS
            ? styles.contentColumn : styles.interactiveContentColumn;
        const description = this._getDescription();

        const notificationStyles = description?.length
            ? styles.notificationWithDescription
            : styles.notification;

        return (
            <Animated.View
                pointerEvents = 'box-none'
                style = { [
                    notificationStyles,
                    {
                        // @ts-ignore
                        opacity: this.state.notificationContainerAnimation
                    }
                ] }>
                <View style = { contentColumnStyles }>
                    { this._mapAppearanceToIcon() }
                    <View
                        pointerEvents = 'box-none'
                        style = { styles.contentContainer }>
                        { this._renderContent() }
                    </View>
                    <View style = { styles.btnContainer }>
                        { this._mapAppearanceToButtons() }
                    </View>
                </View>
                <IconButton
                    color = { BaseTheme.palette.icon04 }
                    onPress = { this._onDismissed }
                    src = { IconCloseLarge }
                    type = { BUTTON_TYPES.TERTIARY } />
            </Animated.View>
        );
    }

    /**
     * Renders the notification's content. If the title or title key is present
     * it will be just the title. Otherwise it will fallback to description.
     *
     * @returns {Array<ReactElement>}
     * @private
     */
    _renderContent() {
        // @ts-ignore
        const { t, title, titleArguments, titleKey } = this.props;
        const titleText = title || (titleKey && t(titleKey, titleArguments));
        const description = this._getDescription();

        if (description?.length) {
            return (
                <>
                    <Text style = { styles.contentTextTitle }>
                        { titleText }
                    </Text>
                    {
                        description.map((line, index) => (
                            <Text
                                key = { index }
                                style = { styles.contentText }>
                                { replaceNonUnicodeEmojis(line) }
                            </Text>
                        ))
                    }
                </>
            );
        }

        return (
            <Text style = { styles.contentTextTitle }>
                { titleText }
            </Text>
        );
    }

    _getDescription: () => Array<string>;

    _onDismissed: () => void;
}


// @ts-ignore
export default translate(Notification);
