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 {withPusher} from "../../component/PushToApi/Pusher";

import {withTheme, injectSheet} from '../../lib/theme';
import {ApiRequest, DELETE, GET, PUT} from '../../lib/ApiRequest';
import i18n from "../../lib/i18n";
import ButtonInteractiveDelete from "../../component/ButtonInteractiveDelete";

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 apiArticle from './ApiArticle';

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.Component {

    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) {
        this.setState({loaded: 'progress'});
        (new ApiRequest('api', GET, 'content/article/' + this.props.match.params.section + '/' + this.props.match.params.article))
            .debug(true)
            .header({})
            .exec()
            .then((res) => {
                if(res && res.data) {
                    if(res.data) {
                        let hasLocales = false;
                        let locales = [];
                        let localeActive = false;
                        let localesPossible = [];
                        let pageTypesPossible = [];
                        if(res.data.locales) {
                            hasLocales = true;
                            locales = res.data.locales;
                            localeActive = locale ? locale : res.data.localeDefault;
                            localesPossible = res.data.localesPossible;
                            pageTypesPossible = res.data.pageTypesPossible;

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

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

    pushDelete = () => {
        const endpoint = 'content/article/' + this.props.match.params.section + '/' + this.props.match.params.article;

        this.props.addPushing(
            {
                name: 'pushDelete',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('delete', 'progress')});

                    (new ApiRequest('api', DELETE, endpoint))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .then((data) => {
                if(data.error) {
                    this.setState({saving: this.createUpdatedSaving('delete', 'error')});
                    return;
                }

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

                apiArticle.triggerList();

                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 endpoint = 'content/article/' + this.props.match.params.article + '/locale/' + localeActive;

        this.props.addPushing(
            {
                name: 'pushNewLocale',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('new_locale', 'progress')});

                    (new ApiRequest('api', PUT, endpoint, {'page_type': pageType}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .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 endpoint = 'content/article-data/' + articleInfo.data[localeActive].id;

        this.props.addPushing(
            {
                name: 'pushDeleteLocale',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('delete_locale', 'progress')});

                    (new ApiRequest('api', DELETE, endpoint))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .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 endpoint = 'content/article/' + this.props.match.params.section + '/' + this.props.match.params.article;

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

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

        this.props.addPushing(
            {
                name: 'pushBaseData',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('base_edit', 'progress')});
                    (new ApiRequest('api', PUT, endpoint, data))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .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);
                }

                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 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.props.addPushing(
            {
                name: 'pushMeta',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('meta', 'progress')});

                    (new ApiRequest('api', PUT, endpoint, {meta: meta}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .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 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.props.addPushing(
            {
                name: 'pushMainText',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('mainText', 'progress')});
                    (new ApiRequest('api', PUT, endpoint, {mainText: text}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .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 {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.props.addPushing(
            {
                name: 'pushDocTree',
                context: endpoint,
                push: (resolve, reject) => {
                    this.setState({saving: this.createUpdatedSaving('docTree', 'progress')});
                    (new ApiRequest('api', PUT, endpoint, {docTree: tree}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch(() => {
                            reject();
                        });
                }
            })
            .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 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
                                                localesPossible={localesPossible}
                                                articleInfo={articleInfo}
                                                articleData={articleData}
                                                pushBaseData={this.pushBaseData}
                                                open={this.state.openBaseEdit}
                                                saving={this.state.saving.base_edit}
                                            />
                                            <ArticleDetailLocaleSwitch
                                                localesPossible={localesPossible}
                                                locales={locales}
                                                localeActive={localeActive}
                                                localeSwitch={this.localeSwitch}
                                            />
                                            <ArticleDetailLocaleHead
                                                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 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 open={this.state.openHelp}
                                                   toggle={this.openHelp}
                                />

                                {articleData.meta ?
                                    <ArticleDetailMeta 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 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 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')(withPusher(withTheme(injectSheet(theming)(ArticleDetail))));