import PropTypes from 'prop-types';
import React from 'react';
import {connect} from 'react-redux';
import {defineMessages, injectIntl, intlShape} from 'react-intl';

import {
    getIsAnyCreatingNewState,
    getIsShowingWithoutId
} from '../reducers/project-state';
import {setProjectTitle} from '../reducers/project-title';

const messages = defineMessages({
    defaultProjectTitle: {
        id: 'tw.gui.defaultProjectTitle',
        description: 'Default title for project',
        defaultMessage: 'Project'
    }
});

/* Higher Order Component to get and set the project title
 * @param {React.Component} WrappedComponent component to receive project title related props
 * @returns {React.Component} component with project loading behavior
 */
const TitledHOC = function (WrappedComponent) {
    class TitledComponent extends React.Component {
        componentDidMount () {
            this.handleReceivedProjectTitle(this.props.projectTitle);
        }
        componentDidUpdate (prevProps) {
            if (this.props.projectTitle !== prevProps.projectTitle) {
                this.handleReceivedProjectTitle(this.props.projectTitle);
            }
            // if project is a new default project, and has loaded,
            if (this.props.isShowingWithoutId && prevProps.isAnyCreatingNewState) {
                // reset title to default
                const defaultProjectTitle = this.handleReceivedProjectTitle();
                this.props.onUpdateProjectTitle(defaultProjectTitle, true);
            }
            // if the projectTitle hasn't changed, but the reduxProjectTitle
            // HAS changed, we need to report that change to the projectTitle's owner
            if (this.props.reduxProjectTitle !== prevProps.reduxProjectTitle &&
                this.props.reduxProjectTitle !== this.props.projectTitle) {
                const defaultProjectTitle = this.props.intl.formatMessage(messages.defaultProjectTitle);
                this.props.onUpdateProjectTitle(
                    this.props.reduxProjectTitle,
                    this.props.reduxProjectTitle === defaultProjectTitle
                );
            }
        }
        handleReceivedProjectTitle (requestedTitle) {
            let newTitle = requestedTitle;
            let isDefault = false;
            if (newTitle === null || typeof newTitle === 'undefined') {
                newTitle = this.props.intl.formatMessage(messages.defaultProjectTitle);
                isDefault = true;
            }
            this.props.onChangedProjectTitle(newTitle, isDefault);
            return newTitle;
        }
        render () {
            const {
                /* eslint-disable no-unused-vars */
                intl,
                isAnyCreatingNewState,
                isShowingWithoutId,
                onChangedProjectTitle,
                // for children, we replace onUpdateProjectTitle with our own
                onUpdateProjectTitle,
                // we don't pass projectTitle prop to children -- they must use
                // redux value
                projectTitle,
                reduxProjectTitle,
                /* eslint-enable no-unused-vars */
                ...componentProps
            } = this.props;
            return (
                <WrappedComponent
                    {...componentProps}
                />
            );
        }
    }

    TitledComponent.propTypes = {
        intl: intlShape,
        isAnyCreatingNewState: PropTypes.bool,
        isShowingWithoutId: PropTypes.bool,
        onChangedProjectTitle: PropTypes.func,
        onUpdateProjectTitle: PropTypes.func,
        projectTitle: PropTypes.string,
        reduxProjectTitle: PropTypes.string
    };

    TitledComponent.defaultProps = {
        onUpdateProjectTitle: () => {}
    };

    const mapStateToProps = state => {
        const loadingState = state.scratchGui.projectState.loadingState;
        return {
            isAnyCreatingNewState: getIsAnyCreatingNewState(loadingState),
            isShowingWithoutId: getIsShowingWithoutId(loadingState),
            reduxProjectTitle: state.scratchGui.projectTitle
        };
    };

    const mapDispatchToProps = dispatch => ({
        onChangedProjectTitle: title => dispatch(setProjectTitle(title))
    });

    return injectIntl(connect(
        mapStateToProps,
        mapDispatchToProps
    )(TitledComponent));
};

export {
    TitledHOC as default
};
