import React from 'react';
import {withNamespaces} from 'react-i18next';
import {MdEdit} from 'react-icons/md';
import {Redirect} from 'react-router-dom';

import Loading from "../../component/Loading";

import {withTheme, injectSheet} from '../../lib/theme';
import {i18n} from "../../lib/i18n";
import ButtonInteractiveDelete from "../../component/ButtonInteractiveDelete";
import {cancelPromise} from "../../component/cancelPromise";

import ArticleDetailHead from './ArticleDetailHead';
import ArticleDetailLocaleHead from './ArticleDetailLocaleHead';
import ArticleDetailLocaleSwitch from './ArticleDetailLocaleSwitch';
import ArticleDetailBaseEdit from './ArticleDetailBaseEdit';
import ArticleDetailHelp from './ArticleDetailHelp';
import ArticleDetailMeta from './ArticleDetailMeta';
import ArticleDetailMainText from './ArticleDetailMainText';
import ArticleDetailDocTree from './ArticleDetailDocTree';
import ArticleDetailSavingChart from './ArticleDetailSavingChart';
import {storeArticle} from "./Stores/Article";

const theming = theme => ({
    button: {
        fontSize: '0.875rem',
        background: 'none',
        padding: theme.gutter.base + 'px ' + theme.gutter.base * 2 + 'px',
        '&:first-child': {
            paddingLeft: 0,
        },
        '&:last-child': {
            paddingRight: 0,
        }
    },
    subTitle: {
        margin: 0
        //margin: '-12px 0 6px 0',
    }
});

const styling = {
    button: theme => ({
        color: theme.linkColor
    }),
};

const initialState = {
    articleInfo: {},
    hasLocales: false,
    localeActive: false,
    localesPossible: [],
    locales: [],
    pageTypesPossible: [],
    loaded: false,
    openBaseEdit: false,
    openMeta: false,
    openHelp: false,
    cacheid: false,
    moveToSection: false,
    saving: {
        new_locale: false,
        delete: false,
        delete_locale: false,
        base_edit: false,
        meta: false,
        mainText: false,
        docTree: false,
    },
};

class ArticleDetail extends React.PureComponent {

    state = initialState;

    componentWillUnmount() {
        this.setState(initialState);
    }

    //
    // Api Fetch and Push

    createUpdatedSaving(name, val) {
        const saving = {...this.state.saving};
        saving[name] = val;
        return saving;
    }

    fetch(locale = false) {
        const {loadArticle, cancelPromise} = this.props;

        this.setState({loaded: 'progress'});
        cancelPromise(loadArticle(this.props.match.params.section, this.props.match.params.article))
            .then(data => {
                let hasLocales = false;
                let locales = [];
                let localeActive = false;
                let localesPossible = [];
                let pageTypesPossible = [];
                if(data.locales) {
                    hasLocales = true;
                    locales = data.locales;
                    localeActive = locale ? locale : data.localeDefault;
                    localesPossible = data.localesPossible;
                    pageTypesPossible = data.pageTypesPossible;

                    if(-1 === locales.indexOf(localeActive) && locales[0]) {
                        localeActive = locales[0];
                    }
                }

                if([] === data.doc_tree) {
                    data.doc_tree = {};
                }
                this.setState({
                    articleInfo: data,
                    hasLocales,
                    locales,
                    localeActive,
                    localesPossible,
                    pageTypesPossible,
                    loaded: true,
                    cacheid: '#' + this.props.match.params.section + '##' + this.props.match.params.article + '#'
                });
            })
            .catch(res => {
                if(!res.cancelled) {
                    this.setState({
                        loaded: 'error'
                    });
                }
            });
    }

    pushDelete = () => {
        const {deleteArticle, cancelPromise} = this.props;

        this.setState({saving: this.createUpdatedSaving('delete', 'progress')});
        cancelPromise(deleteArticle(this.props.match.params.section, this.props.match.params.article))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('delete', 'error')});
                    return;
                }

                this.setState({
                    saving: this.createUpdatedSaving('delete', 'success'),
                });

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('delete', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('delete', 'error')});
                }
            });
    };

    pushNewLocale = (pageType) => {
        const {localeActive} = this.state;
        const {createArticleLocale, cancelPromise} = this.props;

        this.setState({saving: this.createUpdatedSaving('new_locale', 'progress')});
        cancelPromise(createArticleLocale(this.props.match.params.article, localeActive, pageType))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('new_locale', 'error')});
                    return;
                }

                this.setState({
                    saving: this.createUpdatedSaving('new_locale', 'success'),
                });
                this.fetch(localeActive);

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('new_locale', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('new_locale', 'error')});
                }
            });
    };

    pushDeleteLocale = () => {
        const {localeActive, articleInfo} = this.state;
        const {deleteArticleLocale, cancelPromise} = this.props;

        this.setState({saving: this.createUpdatedSaving('delete_locale', 'progress')});
        cancelPromise(deleteArticleLocale(articleInfo.data[localeActive].id))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('delete_locale', 'error')});
                    return;
                }

                this.setState({
                    saving: this.createUpdatedSaving('delete_locale', 'success'),
                });
                this.fetch(localeActive);

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('delete_locale', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('delete_locale', 'error')});
                }
            });
    };

    pushBaseData = (name, tag, section = false) => {
        const {localeActive, articleInfo} = this.state;
        const {updateArticleBaseData, loadArticleList, cancelPromise} = this.props;

        const moveToSection = (section && articleInfo.section !== section);
        const renaming = (name && articleInfo.name !== name);

        const data = {
            name,
            tag,
        };
        if(section) {
            data.section = section
        }

        this.setState({saving: this.createUpdatedSaving('base_edit', 'progress')});
        cancelPromise(updateArticleBaseData(this.props.match.params.section, this.props.match.params.article, data))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('base_edit', 'error')});
                    return;
                }

                this.setState({
                    saving: this.createUpdatedSaving('base_edit', 'success'),
                    openBaseEdit: false
                });
                if(moveToSection) {
                    this.setState({
                        moveToSection: section,
                    });
                    setTimeout(() => {
                        this.setState({
                            moveToSection: false,
                        })
                    }, 0);
                } else {
                    this.fetch(localeActive);
                }

                if(renaming) {
                    loadArticleList(this.props.match.params.section, true);
                }

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('base_edit', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('base_edit', 'error')});
                }
            });
    };

    pushMeta = (meta) => {
        const {hasLocales, articleInfo, localeActive} = this.state;
        const {updateArticleMeta, cancelPromise} = this.props;

        const endpoint = hasLocales ?
            'content/article-data/' + articleInfo.data[localeActive].id :
            'content/article/' + this.props.match.params.section + '/' + this.props.match.params.article;

        if(hasLocales) {
            // data state updating; not needed for not-localised as there no switching with persistent mounted articleDetail
            const artInf = {...articleInfo};
            const artInfData = {...artInf.data};
            const artInfDataLocale = {...artInfData[localeActive]};
            artInfDataLocale.meta = Object.assign(artInfDataLocale.meta, meta);
            artInfData[localeActive] = artInfDataLocale;
            artInf.data = artInfData;
            this.setState({articleInfo: artInf})
        }

        this.setState({saving: this.createUpdatedSaving('meta', 'progress')});

        cancelPromise(updateArticleMeta(endpoint, meta))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('meta', 'error')});
                    return;
                }

                this.setState({saving: this.createUpdatedSaving('meta', 'success')});

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('meta', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('meta', 'error')});
                }
            });
    };

    pushMainText = (text) => {
        const {hasLocales, articleInfo, localeActive} = this.state;
        const {updateArticleMainText, cancelPromise} = this.props;

        const endpoint = hasLocales ?
            'content/article-data/' + articleInfo.data[localeActive].id :
            'content/article/' + this.props.match.params.section + '/' + this.props.match.params.article;

        if(hasLocales) {
            // data state updating; not needed for not-localised as there no switching with persistent mounted articleDetail
            const artInf = {...articleInfo};
            const artInfData = {...artInf.data};
            const artInfDataLocale = {...artInfData[localeActive]};
            artInfDataLocale.mainText = text;
            artInfData[localeActive] = artInfDataLocale;
            artInf.data = artInfData;
            this.setState({articleInfo: artInf})
        }


        this.setState({saving: this.createUpdatedSaving('mainText', 'progress')});
        cancelPromise(updateArticleMainText(endpoint, text))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('mainText', 'error')});
                    return;
                }

                this.setState({saving: this.createUpdatedSaving('mainText', 'success')});

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('mainText', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('mainText', 'error')});
                }
            });
    };

    pushDocTree = (tree) => {
        const {updateArticleDocTree, cancelPromise} = this.props;
        const {hasLocales, articleInfo, localeActive} = this.state;

        const endpoint = hasLocales ?
            'content/article-data/' + articleInfo.data[localeActive].id :
            'content/article/' + this.props.match.params.section + '/' + this.props.match.params.article;

        if(hasLocales) {
            // data state updating; not needed for not-localised as there no switching with persistent mounted articleDetail
            const artInf = {...articleInfo};
            const artInfData = {...artInf.data};
            const artInfDataLocale = {...artInfData[localeActive]};
            artInfDataLocale.docTree = tree;
            artInfData[localeActive] = artInfDataLocale;
            artInf.data = artInfData;
            this.setState({articleInfo: artInf})
        }

        this.setState({saving: this.createUpdatedSaving('docTree', 'progress')});

        cancelPromise(updateArticleDocTree(endpoint, tree))
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('docTree', 'error')});
                    return;
                }

                this.setState({saving: this.createUpdatedSaving('docTree', 'success')});

                setTimeout(() => {
                    this.setState({saving: this.createUpdatedSaving('docTree', false)});
                }, 4000);
            })
            .catch((data) => {
                if(!data.cancelled) {
                    this.setState({saving: this.createUpdatedSaving('docTree', 'error')});
                }
            });
    };

    //
    // Open Toggles

    openBaseEdit = () => {
        this.setState({
            openBaseEdit: !this.state.openBaseEdit
        });
    };

    openMeta = () => {
        this.setState({
            openMeta: !this.state.openMeta
        });
    };

    openHelp = () => {
        this.setState({
            openMeta: !this.state.openMeta
        });
    };

    //
    // Default Lifecycles

    /*shouldComponentUpdate(nextProps, nextState) {

        return true;
    }*/

    componentDidUpdate(prevProps) {
        if(prevProps.match.params.section !== this.props.match.params.section ||
            prevProps.match.params.article !== this.props.match.params.article) {
            this.fetch();
        }
    }

    componentDidMount() {
        this.fetch();
    }

    localeSwitch = (locale) => {
        if(locale !== this.state.localeActive) {
            this.setState({
                localeActive: locale
            })
        }
    };

    render() {
        const {t, theme, classes, match} = this.props;
        const {
            hasLocales, locales, localeActive, localesPossible,
            pageTypesPossible,
            articleInfo
        } = this.state;

        const section = match.params.section;
        const article = match.params.article;

        /**
         * If the locale exists in the locales of the article
         * @var {boolean} activeLocaleExists
         */
        const activeLocaleExists = (hasLocales && locales && -1 !== locales.indexOf(localeActive));
        /**
         * If the locale is valid as a locale (e.g. activeLocale is not allowed from API but somehow was submitted from API)
         * @var {boolean} activeLocalePossible
         */
        const activeLocalePossible = (hasLocales && localesPossible && -1 !== localesPossible.indexOf(localeActive));
        const articleData = (
            hasLocales ?
                activeLocaleExists ? articleInfo.data[localeActive] : {} :
                articleInfo.data ? articleInfo.data : {}
        );

        // only show error when using a non-localised api OR on localised only when the active locale exists
        const showDataExistenceError = (!hasLocales || (hasLocales && activeLocaleExists));

        return (
            <React.Fragment>
                {
                    (
                        this.state.moveToSection &&
                        this.props.match.params.section !== this.state.moveToSection
                    ) ? <Redirect to={'/' + i18n.languages[0] + '/content/' + this.state.moveToSection + '/' + this.props.match.params.article}/>
                        : null
                }
                {
                    (
                        'success' === this.state.saving.delete
                    ) ? <Redirect to={'/' + i18n.languages[0] + '/content/' + this.props.match.params.section}/>
                        : null
                }

                {true !== this.state.loaded ? <h1>{t('title')}</h1> : null}
                {
                    true === this.state.loaded ?
                        (
                            <React.Fragment>

                                <ArticleDetailSavingChart
                                    t={t}
                                    saving={this.state.saving}/>

                                <div className={classes.wrapperHead}>
                                    <h1>{t('title')}</h1>
                                    {articleInfo && articleInfo.id ?
                                        <div style={{display: 'flex', alignItems: 'center', margin: theme.gutter.base * -4 + 'px 0 ' + theme.gutter.base * 2 + 'px 0'}}>
                                            <h2 className={classes.subTitle}>{articleInfo.name}</h2>

                                            {hasLocales ?
                                                <React.Fragment>
                                                    <button onClick={this.openBaseEdit}
                                                            style={{marginLeft: theme.gutter.base + 'px'}}
                                                    ><MdEdit color={theme.textColor} size={'1em'}/></button>

                                                    <ButtonInteractiveDelete onClick={this.pushDelete}
                                                                             style={{
                                                                                 fontSize: '0.875rem',
                                                                                 color: theme.textColor,
                                                                                 marginLeft: 'auto',
                                                                                 display: 'flex',
                                                                                 alignItems: 'center'
                                                                             }}
                                                    ><span style={{marginRight: theme.gutter.base + 'px'}}>{t('edit-base.btn-delete-article')}</span></ButtonInteractiveDelete>

                                                    {('progress' === this.state.saving.delete || 'error' === this.state.saving.delete ?
                                                        <Loading style={{
                                                            wrapper: {margin: 0},
                                                            item: ('error' === this.state.saving.delete ? {borderColor: theme.errorColor} : {}),
                                                        }}/> :
                                                        null)}
                                                </React.Fragment>
                                                : null}
                                        </div>
                                        : <p>unkown error</p>}

                                    {hasLocales ?
                                        <React.Fragment>
                                            <ArticleDetailBaseEdit
                                                t={t}
                                                localesPossible={localesPossible}
                                                articleInfo={articleInfo}
                                                articleData={articleData}
                                                pushBaseData={this.pushBaseData}
                                                open={this.state.openBaseEdit}
                                                saving={this.state.saving.base_edit}
                                            />
                                            <ArticleDetailLocaleSwitch
                                                t={t}
                                                localesPossible={localesPossible}
                                                locales={locales}
                                                localeActive={localeActive}
                                                localeSwitch={this.localeSwitch}
                                            />
                                            <ArticleDetailLocaleHead
                                                t={t}
                                                localesPossible={localesPossible}
                                                localeActive={localeActive}
                                                pageTypesPossible={pageTypesPossible}
                                                pushNewLocale={this.pushNewLocale}
                                                pushDeleteLocale={this.pushDeleteLocale}
                                                activeLocalePossible={activeLocalePossible}
                                                activeLocaleExists={activeLocaleExists}
                                                savingDelete={this.state.saving.delete_locale}
                                                savingNew={this.state.saving.new_locale}
                                            />
                                        </React.Fragment>
                                        : null}

                                    <ArticleDetailHead
                                        t={t}
                                        data={articleData}/>

                                    <div className={'nav'}>
                                        {articleData.meta ?
                                            <button onClick={this.openMeta} className={classes.button} style={styling.button(theme)}>{this.state.openMeta ? t('nav.editmeta-hide') : t('nav.editmeta')}</button> : null}
                                        {/*<button onClick={this.openHelp} className={classes.button} style={styling.button(theme)}>{t('nav.openhelp')}</button>*/}
                                    </div>
                                </div>

                                <ArticleDetailHelp
                                    t={t}
                                    open={this.state.openHelp}
                                    toggle={this.openHelp}
                                />

                                {articleData.meta ?
                                    <ArticleDetailMeta
                                        t={t}
                                        meta={articleData.meta}
                                        open={this.state.openMeta}
                                        section={section}
                                        article={article}
                                        cacheid={this.state.cacheid}
                                        saveFn={this.pushMeta}
                                        saving={this.state.saving.meta}
                                    /> :
                                    showDataExistenceError ? <p>{t('view-error.meta')}</p> : null}

                                {articleData.mainText || '' === articleData.mainText ?
                                    <ArticleDetailMainText
                                        t={t}
                                        content={articleData.mainText}
                                        section={section}
                                        article={article}
                                        saveFn={this.pushMainText}
                                        saving={this.state.saving.mainText}
                                    /> :
                                    showDataExistenceError ? <p>{t('view-error.main-text')}</p> : null}

                                {articleData.meta && articleData['docTree'] && articleData['page_type'] ?
                                    <ArticleDetailDocTree
                                        t={t}
                                        section={section}
                                        article={article}
                                        pageType={articleData['page_type']}
                                        docTree={articleData['docTree']}
                                        saveFn={this.pushDocTree}
                                        saving={this.state.saving.docTree}
                                    /> :
                                    showDataExistenceError ? <p>{t('view-error.article-without-doctree')}</p> : null}

                            </React.Fragment>
                        ) :
                        ('progress' === this.state.loaded || 'error' === this.state.loaded ?
                            <Loading style={{
                                wrapper: {margin: 0},
                                item: ('error' === this.state.loaded ? {borderColor: this.props.theme.errorColor} : {}),
                            }}/> :
                            null)
                }
            </React.Fragment>
        )
    };
}

export default withNamespaces('page--content-article')(storeArticle(cancelPromise(withTheme(injectSheet(theming)(ArticleDetail)))));