import React from 'react';
import { TextInput, Button, Icon, Spin } from 'lego-on-react';
import block from 'bem-cn';
import PencilOutlineIcon from 'components/Icon/PencilOutline';
import CheckIcon from 'components/Icon/Check';
import CrossIcon from 'components/Icon/Cross';
import Modal from 'components2/Modal';
import isInsideBlock from 'lib2/isInsideBlock';
import './index.css';
import './hint.css';

const b = block('inline-editable');

export default class InlineEditable extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            value: props.value,
            editMode: props.editMode,
        };

        this._onOuterClick = this._onOuterClick.bind(this);
        this._onChange = this._onChange.bind(this);

        this._init = this._init.bind(this);
        this._edit = this._edit.bind(this);
        this._confirm = this._confirm.bind(this);
        this._submit = this._submit.bind(this);
        this._cancel = this._cancel.bind(this);
    }

    componentWillUnmount() {
        this._unmounted = true;

        document.removeEventListener('click', this._onOuterClick);
    }

    componentDidUpdate(prevProps) {
        let { value, editMode } = this.props;

        if (value !== prevProps.value) {
            this.setState({
                value,
            });
        }

        if (editMode !== prevProps.editMode) {
            this.setState({
                editMode,
            });
        }
    }

    _onChange(value) {
        this.setState({
            value,
        });

        let { onChange } = this.props;

        if (onChange) {
            onChange(value);
        }
    }

    _onOuterClick({ target }) {
        if (!this.state.editMode || !this._element) {
            return;
        }

        if (!this._element.contains(target) && !isInsideBlock(b('confirm-modal'), target)) {
            this._cancel();
        }
    }

    _init(element) {
        if (!this._element) {
            this._element = element;

            document.addEventListener('click', this._onOuterClick);
        }
    }

    _edit() {
        this.setState({
            editMode: true,
            originalValue: this.state.value,
        });
    }

    _confirm() {
        this.setState({
            confirmOpen: true,
        });
    }

    _submit() {
        let { onSubmit } = this.props;
        let submit = onSubmit && onSubmit(this.state.value);

        if (!submit || !(submit instanceof Promise)) {
            return this.setState({
                editMode: false,
                confirmOpen: false,
            });
        }

        this.setState({
            busy: true,
        });

        submit.finally(() => {
            if (!this._unmounted) {
                this.setState({
                    busy: false,
                    editMode: false,
                    confirmOpen: false,
                });
            }
        });
    }

    _cancel() {
        this.setState({
            editMode: false,
            confirmOpen: false,
            value: this.state.originalValue,
        });
    }

    render() {
        let {
            busy,
            value,
            originalValue,
            editMode,
            confirmOpen,
        } = this.state;

        let {
            children,
            cls,
            id,
            editable,
            placeholder,
            hint,
            confirmType,
            confirmTitle,
            confirmMessage,
            confirmButtonCaption,
        } = this.props;

        let withConfirmation = confirmTitle || confirmMessage;

        return (
            <span
                className={b({ 'edit-mode': editMode, busy }).mix(cls)}
                ref={this._init}
            >
                <span className={b('value')}>
                    {value}
                </span>
                {editable && (
                    <React.Fragment>
                        <span className={b('editor')}>
                            {children || (
                                <TextInput
                                    cls={b('input')}
                                    theme="normal"
                                    size="m"
                                    text={value}
                                    autoComplete={false}
                                    onChange={this._onChange}
                                    placeholder={placeholder}
                                    hint={hint}
                                    id={id}
                                />
                            )}
                            {hint && (
                                <span className={b('hint')}>
                                    <span dangerouslySetInnerHTML={{ __html: hint }} />
                                </span>
                            )}
                        </span>
                        <span className={b('controls')}>
                            <Button
                                cls={b('button', { type: 'edit' })}
                                theme="clear"
                                size="m"
                                onClick={this._edit}
                            >
                                <Icon
                                    cls={b('icon', { type: 'edit' })}
                                    glyph="yes"
                                >
                                    <PencilOutlineIcon />
                                </Icon>
                            </Button>
                            <Button
                                cls={b('button', { type: 'apply' })}
                                theme="clear"
                                size="m"
                                onClick={withConfirmation ? this._confirm : this._submit}
                                disabled={busy || value === originalValue}
                            >
                                <Icon
                                    cls={b('icon', { type: 'apply' })}
                                    glyph="yes"
                                >
                                    <CheckIcon />
                                </Icon>
                            </Button>
                            <Button
                                cls={b('button', { type: 'cancel' })}
                                theme="clear"
                                size="m"
                                onClick={this._cancel}
                                disabled={busy}
                            >
                                <Icon
                                    cls={b('icon', { type: 'cancel' })}
                                    glyph="yes"
                                >
                                    <CrossIcon />
                                </Icon>
                            </Button>
                            {!withConfirmation && (
                                <Spin
                                    cls={b('spin')}
                                    size="xxs"
                                    progress
                                />
                            )}
                        </span>
                        {withConfirmation && (
                            <Modal
                                cls={b('confirm-modal')}
                                visible={confirmOpen}
                            >
                                {confirmTitle && (
                                    <Modal.Title>
                                        {confirmTitle}
                                    </Modal.Title>
                                )}
                                <Modal.CloseButton onClick={this._cancel} />
                                {confirmMessage && (
                                    <Modal.Body type={confirmType}>
                                        <div dangerouslySetInnerHTML={{ __html: confirmMessage }} />
                                    </Modal.Body>
                                )}
                                <Modal.ConfirmActions
                                    onConfirm={this._submit}
                                    onCancel={this._cancel}
                                    confirmCaption={confirmButtonCaption}
                                />
                                <Modal.Busy visible={busy} />
                            </Modal>
                        )}
                    </React.Fragment>
                )}
            </span>
        );
    }
}
