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

const StoreBlockContext = React.createContext({});

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

        this.state = {
            blocks: {},
            blockList: false,
            loadingBlock: {},
            loadingBlockList: false,
            loadBlock: this.loadBlock,
            loadBlockList: this.loadBlockList,
            isBlockLoaded: this.isBlockLoaded
        };
    }

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

    updateBlockLoaded = (block, status) => {
        const loadingBlock = {...this.state.loadingBlock};
        loadingBlock[block] = status;
        this.setState({loadingBlock});
    };

    loadBlock = (block, forceLoad = false) => {
        if((!isUndefined(this.state.blocks[block]) && true === this.isBlockLoaded(block)) && !forceLoad) {
            return Promise.resolve(this.state.blocks[block]);
        } else if((isUndefined(this.state.blocks[block]) && false === this.isBlockLoaded(block)) || forceLoad) {

            // direct state mutating needed for to fast browser mounting
            // eslint-disable-next-line
            this.state.loadingBlock[block] = 'progress';
            this.updateBlockLoaded(block, 'progress');

            return (new ApiRequest('api', GET, 'content/block/' + block))
                .debug(true)
                .exec()
                .then((res) => {
                    if(res && res.data) {
                        const blocks = {...this.state.blocks};
                        blocks[block] = res.data;

                        this.setState({
                            blocks,
                        });
                        this.updateBlockLoaded(block, true);

                        return res.data;
                    } else {
                        this.updateBlockLoaded(block, 'error');
                    }
                    return Promise.reject();
                })
                .catch((err) => {
                    this.props.handleApiFail(err, 'loading Block');
                    if(err && !err.cancelled) {
                        this.updateBlockLoaded(block, 'error');
                    }
                    return Promise.reject();
                });
        } else if('progress' === this.isBlockLoaded(block)) {
            return Promise.reject({waitForBlock: true})
        } else {
            return Promise.reject();
        }
    };

    loadBlockList = (forceLoad = false) => {
        if((this.state.blockList && true === this.state.loadingBlockList) && !forceLoad) {
            return Promise.resolve(this.state.blockList);
        } else if((!this.state.blockList && false === this.state.loadingBlockList) || forceLoad) {

            this.setState({loadingBlockList: 'progress'});
            return (new ApiRequest('api', GET, 'content/blocks'))
                .debug(true)
                .header({})
                .exec()
                .then((res) => {
                    if(res && res.data) {
                        this.setState({
                            blockList: res.data,
                        });
                        this.setState({loadingBlockList: true});

                        return Promise.resolve(res.data);
                    } else {
                        this.setState({loadingBlockList: 'error'});
                    }
                    return Promise.reject();
                })
                .catch((err) => {
                    this.props.handleApiFail(err, 'loading BlockList');
                    if(err && !err.cancelled) {
                        this.setState({loadingBlockList: 'error'});
                    }
                    return Promise.reject();
                });
        } else if('progress' === this.state.loadingBlockList) {
            return Promise.reject({waitForBlockList: true})
        } else {
            console.log('General Error in StoreBlock.loadBlockList');
            return Promise.reject();
        }
    };

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

const StoreBlockProvider = cancelPromise(withApiControl(StoreBlockProviderBase));

const storeBlock = withContextConsumer(StoreBlockContext.Consumer);

export {StoreBlockProvider, storeBlock};