import React from 'react';
import {withContextConsumer} from "@formanta/react";
import {ApiRequest, DELETE, GET, POST, PUT} from "../../../lib/ApiRequest";
import {isUndefined} from "@formanta/js";
import {Pushing, withPusher} from '../../../component/Pusher/Pusher';
import {cancelPromise} from "../../../component/cancelPromise";
import {withApiControl} from "../../../component/ApiControl";

const StoreArticleContext = React.createContext({});

class StoreArticleProviderBase extends React.Component {
    constructor(props) {
        super(props);

        this.state = {
            articles: {},
            loadingArticles: {},
            createArticle: this.createArticle,
            createArticleLocale: this.createArticleLocale,
            deleteArticle: this.deleteArticle,
            deleteArticleLocale: this.deleteArticleLocale,
            loadArticle: this.loadArticle,
            loadArticleList: this.loadArticleList,
            isArticleListLoaded: this.isArticleListLoaded,
            updateArticleBaseData: this.updateArticleBaseData,
            updateArticleMeta: this.updateArticleMeta,
            updateArticleMainText: this.updateArticleMainText,
            updateArticleDocTree: this.updateArticleDocTree,
        };
    }

    isArticleListLoaded = (section) => {
        if(isUndefined(this.state.loadingArticles[section])) {
            return false;
        }
        return this.state.loadingArticles[section];
    };

    updateArticleListLoaded = (section, status) => {
        const loadingArticles = {...this.state.loadingArticles};
        loadingArticles[section] = status;
        this.setState({loadingArticles});
    };

    loadArticle = (section, article) => {
        return (new ApiRequest('api', GET, 'content/article/' + section + '/' + article))
            .debug(true)
            .header({})
            .exec()
            .then((res) => {
                if(res && res.data) {
                    if(res.data.error) {
                        return Promise.reject(res);
                    }
                    return res.data;
                } else {
                    return Promise.reject(res);
                }
            })
            .catch((err) => {
                this.props.handleApiFail(err, 'loadArticle');
                return Promise.reject(err);
            });
    };

    loadArticleList = (section, forceLoad = false) => {
        if(isUndefined(this.state.articles[section]) || forceLoad) {

            this.updateArticleListLoaded(section, 'progress');
            (new ApiRequest('api', GET, 'content/section/' + section + '/article'))
                .debug(true)
                .exec()
                .then((res) => {
                    if(res && res.data) {
                        const articles = {...this.state.articles};
                        articles[section] = res.data;

                        this.setState({
                            articles,
                        });
                        this.updateArticleListLoaded(section, true);
                    } else {
                        this.updateArticleListLoaded(section, 'error');
                    }
                })
                .catch((err) => {
                    this.props.handleApiFail(err, 'loadArticleList');
                    this.updateArticleListLoaded(section, 'error');
                });
        }
    };

    createArticle = (section, name, tag) => {
        const endpoint = 'content/article';

        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'createArticle',
                endpoint,
                (resolve, reject) => {
                    const data = {
                        name,
                        tag,
                        section
                    };
                    (new ApiRequest('api', POST, endpoint, data))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'createArticle');
                            reject();
                        });
                }
            )
        ).then((data) => {
            if(data.error) {
            } else {
                this.loadArticleList(section, true);
            }
            return data;
        });
    };

    createArticleLocale = (article, locale, pageType) => {
        const endpoint = 'content/article/' + article + '/locale/' + locale;

        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'createArticleLocale',
                endpoint,
                (resolve, reject) => {
                    (new ApiRequest('api', PUT, endpoint, {'page_type': pageType}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'createArticleLocale');
                            reject();
                        });
                }
            )
        );
    };

    deleteArticle = (section, article) => {
        const endpoint = 'content/article/' + section + '/' + article;

        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'deleteArticle',
                endpoint,
                (resolve, reject) => {
                    (new ApiRequest('api', DELETE, endpoint))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'deleteArticle');
                            reject();
                        });
                }
            )
        ).then((data) => {
            if(data.error) {
            } else {
                this.loadArticleList(section, true);
            }
            return data;
        });
    };

    deleteArticleLocale = (article_data_locale_id) => {
        const endpoint = 'content/article-data/' + article_data_locale_id;
        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'deleteArticleLocale',
                endpoint,
                (resolve, reject) => {
                    (new ApiRequest('api', DELETE, endpoint))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'deleteArticleLocale');
                            reject();
                        });
                }
            )
        );
    };

    updateArticleBaseData = (section, article, data) => {
        const {execPushing} = this.props;
        const endpoint = 'content/article/' + section + '/' + article;

        return execPushing(
            new Pushing(
                'updateArticleBaseData',
                endpoint,
                (resolve, reject) => {
                    (new ApiRequest('api', PUT, endpoint, data))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'updateArticleBaseData');
                            reject();
                        });
                }
            )
        );
    };

    updateArticleMeta = (endpoint, meta) => {
        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'updateArticleMeta',
                endpoint,
                (resolve, reject) => {

                    (new ApiRequest('api', PUT, endpoint, {meta: meta}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'updateArticleMeta');
                            reject();
                        });
                }
            )
        );
    };

    updateArticleMainText = (endpoint, text) => {
        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'updateArticleMainText',
                endpoint,
                (resolve, reject) => {
                    (new ApiRequest('api', PUT, endpoint, {mainText: text}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'updateArticleMainText');
                            reject();
                        });
                }
            )
        );
    };

    updateArticleDocTree = (endpoint, tree) => {
        const {execPushing} = this.props;

        return execPushing(
            new Pushing(
                'updateArticleDocTree',
                endpoint,
                (resolve, reject) => {
                    (new ApiRequest('api', PUT, endpoint, {docTree: tree}))
                        .debug(true)
                        .header({})
                        .exec()
                        .then((res) => {
                            if(res && res.data) {
                                resolve(res.data);
                            } else {
                                reject();
                            }
                        })
                        .catch((err) => {
                            this.props.handleApiFail(err, 'updateArticleDocTree');
                            reject();
                        });
                }
            )
        );
    };

    render() {
        return (
            <StoreArticleContext.Provider value={this.state}>
                {this.props.children}
            </StoreArticleContext.Provider>
        );
    }
}

const storeArticle = withContextConsumer(StoreArticleContext.Consumer);

const StoreArticleProvider = cancelPromise(withApiControl(withPusher(StoreArticleProviderBase)));

export {StoreArticleProvider, storeArticle};