import React, {useState} from 'react';
import {ManifestContext} from './ManifestContext';
import {initialState} from './app.state';
import { take } from 'rxjs/operators';
import path from 'ramda/src/path';
import { CoreServices } from '../services';




export const ManifestStateProvider = ({children}) => {
    const [manifest, setManifest] = useState(initialState);
    const svc = new CoreServices();

    const loadAppManifest = (activeApp) => {
        // Make store available to svc on init
       // svc['store'] = store;
        //
        setManifest({
            ...manifest,
            activeApp,
            activeManifestItem: activeApp['manifestItems'][activeApp.startState],
            navigationStack: []
        });
    }; 

    const loadStartState = () => {
      const activeManifestItem = manifest && manifest.activeApp &&  manifest.activeApp['manifestItems'] ?
       manifest.activeApp['manifestItems'][manifest.activeApp.startState] :
       manifest.activeManifestItem;
       const activeNode = activeManifestItem.nodes[activeManifestItem.startNode];
      setManifest({
        ...manifest,
        activeManifestItem,
        activeManifestItemId: activeManifestItem.id,
        activeNode,
        navigationStack: []
    });
    }

    const setActiveApp = (activeApp) => {
        setManifest({
            ...manifest,
            activeApp
        })
    };

    const setActiveManifestItem = (data: {
        pathToFlows: string[];
        appId: string;
        itemId: number | string;
        defaultNodeKey?: string;
        itemOne?: any;
        itemTwo?: any;
      }) => {
          console.log('hello', data)
        checkDeactivateState(
            svc,
            checkActivateState,
            [
                (state, data) => {

                    const { pathToFlows, itemId, defaultNodeKey } = data;
                    const activeApp = state.activeApp;
                    console.log({data})
                    const activeManifestItem = path(pathToFlows, activeApp)[itemId];
                    const startNode = activeManifestItem.itemType === 'flow' ? activeManifestItem['startNode'] : null;
                
                    if (startNode) {
                      const activeNode = defaultNodeKey
                        ? activeManifestItem['nodes'][defaultNodeKey]
                        : activeManifestItem['nodes'][startNode];
                      let navigationStack;
                      if (state.activeNode && !pathToFlows.includes('contextMenu')) {
                        const prevNode = { ...state.activeNode, prevState: state.activeManifestItemId };
                        navigationStack = [...state.navigationStack, prevNode];
                      } else if (pathToFlows.includes('contextMenu')) {
                        navigationStack = [];
                      } else {
                        navigationStack = [];
                      }
                
                      setManifest({
                          ...manifest,
                          activeApp: activeApp,
                          activeManifestItemId: itemId,
                          activeManifestItem,
                          activeNode: { ...activeNode, id: startNode },
                          navigationStack
                      });
                    } else {
                        setManifest({
                            ...manifest,
                            activeApp: activeApp,
                            activeManifestItemId: itemId,
                            activeManifestItem,
                            activeNode: null
                      });
                    }
                  }
              // makeServerCallOnStateFlow, 
              // listenToCallsForLoader,
              // getFullItemOneAfterManifest
            ]
            )(manifest, data);
      };

      const setNextNode = (data) => {
         checkDeactivateNode(
           svc,
           checkActivateNode,
           [
              // set the next node
              (state: any, data) => {
              
                const compKey = data;
                if (state.activeManifestItem.itemType !== 'flow') {
                  return;
                }
                const nodesObj = state.activeManifestItem.nodes;
            
                const activeNode = nodesObj[compKey];
            
                if (Object.is(activeNode, state.activeNode)) {
                  return;
                }
                // If a decision node, don't push to navstack
                if (state && state.activeNode && state.activeNode.nodeType && state.activeNode.nodeType === 'decision') {
                  setManifest({
                      ...manifest,
                      activeNode: { ...activeNode, id: compKey }
                  });
                } else {
                  setManifest({
                      ...manifest,
                      navigationStack: [...state.navigationStack, state.activeNode],
                      activeNode: { ...activeNode, id: compKey }
                  });
                }
              }
              // TODO: makeServerCallOnNode
           ]
         )(manifest, data)
      };

      const setPreviousNode = () => {
          ((state: any) => {
            const navigationStack = state.navigationStack;
            const prevNode = navigationStack.pop();
        
            if (prevNode && state && state.activeManifestItem && state.activeManifestItem.nodes) {
              const prevItemIds = Object.entries(state.activeManifestItem.nodes)
                .filter((node: any) => prevNode['component'] === node[1]['component'])
                .map(data => {
                  if (data && data.length > 0) {
                    return data[0];
                  }
                  return data;
                });
              if (prevItemIds.length > 0) prevNode.id = prevItemIds[0];
            }
        
            if (prevNode && prevNode.prevState) {
              const activeManifestItemId = prevNode.prevState;
              const activeManifestItem = state.manifest.activeApp['manifestItems'][activeManifestItemId];
              setManifest({
                  ...manifest,
                  activeManifestItemId,
                  activeManifestItem,
                  activeNode: prevNode,
                  navigationStack
              });
            } else {
              setManifest({
                  ...manifest,
                  activeNode: prevNode,
                  navigationStack
              });
            }
          })(manifest)
      };

    return (
        <ManifestContext.Provider 
        value={{
            manifest, 
            svc,
            loadAppManifest,
            loadStartState,
            setActiveApp,
            setActiveManifestItem,
            setNextNode,
            setPreviousNode
            }}>
            {children}
        </ManifestContext.Provider>
    );
};




//// CHECK ACTIVATE STATE
export const checkActivateState = (state, data, svc: CoreServices, callbacks: Function[]) => {
    const { pathToFlows, itemId } = data;
    const activeApp = state.activeApp;
    console.log({state, data})
    const activeManifestItem = path(pathToFlows, activeApp)[itemId];
    if (activeManifestItem && activeManifestItem.activateStateGuard) {
        activeManifestItem.activateStateGuard(svc)
        .pipe(take(1))
        .subscribe(canGo => {
            if(canGo) {
                console.log({state, data})
                callbacks.forEach(cb => cb(state, data))
            }
        })
    } else {
        console.log({state, data})
        callbacks.forEach(cb => cb(state, data))
    }
};


// CHECK CURRENT MANIFEST ITEM IF IT CAN BE DEACTIVATED
export const checkDeactivateState = (svc: CoreServices, checkActivateNextState: Function, callbacks: Function[]) => {
return (state, data) => {
    const activeManifestItem =state.activeManifestItem;
    
    if (activeManifestItem && activeManifestItem.deactivateStateGuard) {
        activeManifestItem.deactivateStateGuard(svc)
        .pipe(take(1))
        .subscribe(canGo => {
            if(canGo) {
                if (state && state.activeApp)
                checkActivateNextState(state, data, svc, callbacks);
            }
        })
    } else {
        if (state && state.activeApp) {
            console.log('jiii', activeManifestItem)
            checkActivateNextState(state, data, svc, callbacks);
        }
    }
}
};



//// CHECK ACTIVATE NODE
export const checkActivateNode = (state, data, svc: CoreServices, callbacks: Function[]) => {
  const nodeKey = data;
  const activeManifestItem = state.activeManifestItem;
  const activeNode = activeManifestItem.nodes[nodeKey];
  if (activeNode && activeNode.activateNodeGuard) {
      activeNode.activateNodeGuard(svc)
      .pipe(take(1))
      .subscribe(canGo => {
          if(canGo) {
              callbacks.forEach(cb => cb(state, data))
          }
      })
  } else {
      callbacks.forEach(cb => cb(state, data))
  }
};



// CHECK CURRENT NODE IF IT CAN BE DEACTIVATED
export const checkDeactivateNode = (svc: CoreServices, checkActivateNextNode: Function, callbacks: Function[]) => {
  return (state, data) => {
      const activeNode =state.activeNode;
      
      if (activeNode && activeNode.deactivateNodeGuard) {
          activeNode.deactivateNodeGuard(svc)
          .pipe(take(1))
          .subscribe(canGo => {
              if(canGo) {
                  if (state && state.activeApp)
                  checkActivateNextNode(state, data, svc, callbacks);
              }
          })
      } else {
          if (state && state.activeApp) {
              checkActivateNextNode(state, data, svc, callbacks);
          }
      }
  }
  };



