// 3rd-party libs
import React, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import cloneDeep from 'lodash/cloneDeep';

// Internals
import * as ApiActions from './apiActions';
import useReadmeApi from '@core/hooks/useReadmeApi';

// Components
import { Button, Toggle, Notification, Modal, Title } from '@ui/components';
import { TutorialCard, TutorialModal, TutorialObstacle } from '@ui/compositions';
import ModalBody from '@ui/components/Modal/Body';
import ModalFooter from '@ui/components/Modal/Footer';
import TutorialHero from './components/TutorialHero';

// Constants
import { DEFAULT_TUTORIAL } from '@ui/compositions/Tutorials/Modal/constants/stepDefaults';

// Internal Variable Context
const cmVariableContext =
  typeof window !== 'undefined'
    ? require('@readme/syntax-highlighter/dist/index.js').cmVariableContext
    : React.createContext();

// Style
let classes = {};
/* istanbul ignore next */
if (typeof window !== 'undefined' || typeof _COMPILED_ === 'undefined') classes = require('./style.module.scss');

const PermissionContext = React.createContext(false);
export { cmVariableContext, PermissionContext };

export default function Tutorials(props) {
  const { baseUrl, modalTarget, confirmationTarget, slug, referenceEnabled } = props;

  const [hero, setHero] = useState({});
  const [onboarding, setOnboarding] = useState({});
  const [tutorials, setTutorials] = useState([]);
  const [initialLoad, setInitialLoad] = useState(true);

  const [modalMeta, setModalMeta] = useState({
    open: false,
    action: 'View',
  });
  const [confirmModalState, setConfirmModal] = useState({});
  const [moduleEnabled, setModuleEnabled] = useState(false);
  const [selectedTutorial, setSelectedTutorial] = useState();
  const [isAdmin] = useState(props.isAdmin);

  const modalRef = React.createRef();

  const { response, error, setError, pendingRequest, initRequest } = useReadmeApi(baseUrl);
  const getTutorials = () => ApiActions.getTutorials(initRequest);

  useEffect(() => {
    getTutorials();
  }, []);

  useEffect(() => {
    if (pendingRequest) getTutorials();
  }, [pendingRequest]);

  useEffect(() => {
    if (Object.keys(response).length) setInitialLoad(false);
  }, [response]);

  useEffect(() => {
    if (response.hero) setHero(response.hero);
  }, [response.hero]);

  useEffect(() => {
    if (response.tutorialOnboarding) setOnboarding(response.tutorialOnboarding);
  }, [response.tutorialOnboarding]);

  useEffect(() => {
    if (response.tutorials) setTutorials(response.tutorials);
  }, [response.tutorials]);

  useEffect(() => {
    if ('moduleEnabled' in response) setModuleEnabled(response.moduleEnabled);
  }, [response.moduleEnabled]);

  useEffect(() => {
    if (slug) {
      ApiActions.getTutorialBySlug(initRequest, { slug });
      setTimeout(() => getTutorials());
    }
  }, [slug]);

  useEffect(() => {
    if (response.tutorial && !response.tutorialPublishToggled) {
      setSelectedTutorial(response.tutorial);
      setModalMeta({
        open: true,
        action: 'View',
      });
    }
  }, [response.tutorial]);

  const pushState = pathSlug => {
    const urlRegexp = /https?:\/\//;
    if (!urlRegexp.test(baseUrl)) {
      const uri = pathSlug ? `${baseUrl}/recipes/${pathSlug}` : `${baseUrl}/recipes`;
      // eslint-disable-next-line no-restricted-globals
      history.pushState('', '', uri);
    }
  };

  const openTutorial = (action, tutorial) => {
    setModalMeta({
      open: true,
      action,
    });
    // Allow us to differentiate based on two factors
    // What type of modal action is this? View|Create|Update
    // And is this the first time we're opening it?
    setSelectedTutorial(prevTutorial => {
      const prevId = prevTutorial && prevTutorial._id && prevTutorial._id.toString();
      const newId = (tutorial && tutorial._id && tutorial._id.toString()) || '';

      if (prevId !== newId && action === 'Create') {
        return { ...cloneDeep(DEFAULT_TUTORIAL) };
      } else if (prevId !== newId) {
        pushState(tutorial.slug);
        return { ...tutorial };
      }
      pushState(tutorial.slug);
      // If we're opening the same modal, we don't want to overwrite any previous work
      return prevTutorial;
    });
  };

  const closeTutorialModal = () => {
    pushState();
    setModalMeta(prevMeta => {
      return {
        ...prevMeta,
        open: false,
      };
    });
  };

  const publishTutorial = event => {
    const { published } = event;

    modalRef.current.toggle(true);
    return setConfirmModal({
      title: `Are you sure you want to ${published ? 'publish' : 'unpublish'} this Recipe?`,
      body: published ? 'This will make it viewable all users.' : 'It will no longer be viewable to users.',
      action: ApiActions.updateTutorial.bind(null, initRequest, event),
      buttonText: published ? 'Publish It!' : 'Unpublish Recipe',
    });
  };

  const deleteTutorial = event => {
    modalRef.current.toggle(true);
    return setConfirmModal({
      title: `Are you sure you want to delete ${event.title ? `‘${event.title}’` : 'this Recipe'}?`,
      body: `You cannot undo this action.`,
      action: ApiActions.deleteTutorial.bind(null, initRequest, event),
      buttonText: `Delete Recipe`,
    });
  };

  const makeHero = event => {
    const { _id, published } = event;

    if (published) return ApiActions.makeHero(initRequest, { _id });

    modalRef.current.toggle(true);
    return setConfirmModal({
      title: 'Are you sure you want to feature an unpublished Recipe?',
      body: 'Featuring an unpublished Recipe will publish it. Make sure it’s ready!',
      action: ApiActions.makeHero.bind(null, initRequest, { _id }),
      buttonText: 'Feature It!',
    });
  };

  const defaultNav = e => {
    e.preventDefault();
    if (window) window.open('https://docs.readme.com/recipes/publish-all-docs-in-category', '_blank');
  };

  return (
    <PermissionContext.Provider value={isAdmin}>
      <cmVariableContext.Provider value={props.variables}>
        <div className={classes.Tutorial}>
          <div className={classes['Tutorial-Wrapper']}>
            {!initialLoad && !tutorials.length && (
              <TutorialObstacle
                body="Recipes are task-driven guidance for your API. Try creating a new Recipe for your users!"
                className={modalMeta.open && 'paused'}
                heading="Create a Recipe to Get Started"
              >
                <Button onClick={() => openTutorial('Create')}>Create Recipe</Button>
                <Button bem={{ shale: true }} onClick={defaultNav}>
                  Try Example
                </Button>
              </TutorialObstacle>
            )}
            {tutorials.length > 0 && (
              <React.Fragment>
                {hero && hero.title && <TutorialHero hero={hero} openTutorial={openTutorial} />}
                <section className={classes.TutorialGrid}>
                  {tutorials.map((tutorial, idx) => (
                    <TutorialCard
                      key={`tut-${idx}`}
                      className={classes['TutorialGrid-Card']}
                      deleteTutorial={deleteTutorial}
                      makeHero={makeHero}
                      numTutorials={tutorials.length}
                      openTutorial={openTutorial}
                      publish={publishTutorial}
                      shiftOrder={e => ApiActions.shiftOrder(initRequest, e)}
                      tutorial={tutorial}
                    />
                  ))}
                </section>
              </React.Fragment>
            )}
          </div>
          {isAdmin && (
            <div className={classes.TutorialToolbar}>
              <button className={classes['TutorialToolbar-Button']} type="Button">
                {moduleEnabled ? (
                  <i className={`icon icon-eye ${classes['TutorialToolbar-Button-Icon']}`} />
                ) : (
                  <i className={`icon icon-eye-crossed ${classes['TutorialToolbar-Button-Icon']}`} />
                )}
                <span>
                  Show Recipes
                  <i className={`fa fa-chevron-down ${classes['TutorialToolbar-Button-Arrow']}`} />
                </span>
                <div className={classes['TutorialToolbar-PopoverWrapper']}>
                  <div className={classes['TutorialToolbar-Popover']}>
                    <Toggle
                      checked={moduleEnabled}
                      disabled={!tutorials.length}
                      label="Show Recipes"
                      onChange={() => ApiActions.toggleModule(initRequest)}
                      type="toggle"
                    />
                    <div className={classes['TutorialToolbar-Popover-Description']}>
                      The Recipes view won’t be shown to users until you publish your first Recipe.
                    </div>
                  </div>
                </div>
              </button>
              <button
                className={classes['TutorialToolbar-Button']}
                onClick={() => openTutorial('Create')}
                type="Button"
              >
                <i className={`icon icon-recipes-new ${classes['TutorialToolbar-Button-Icon']}`} />
                Create Recipe
              </button>
            </div>
          )}
        </div>
        {isAdmin && error && (
          <Notification color={'red'} dismissible={true} handleClick={() => setError(null)} position={'top'}>
            <p>{error}</p>
          </Notification>
        )}
        <TutorialModal
          action={modalMeta.action}
          baseUrl={baseUrl}
          closeTutorialModal={closeTutorialModal}
          confirmModal={modalRef}
          moduleEnabled={moduleEnabled}
          onboarding={onboarding}
          open={modalMeta.open}
          referenceEnabled={referenceEnabled}
          requestDataRefresh={() => getTutorials()}
          setConfirmModal={setConfirmModal}
          target={modalTarget}
          tutorial={selectedTutorial}
        />
        <Modal
          ref={modalRef}
          className={classes.TutorialConfirmation}
          size="sm"
          target={confirmationTarget}
          verticalCenter
        >
          <ModalBody>
            <Title className={classes['TutorialConfirmation-Title']} level={4}>
              {confirmModalState.title}
            </Title>
            <p className={classes['TutorialConfirmation-Description']}>{confirmModalState.body}</p>
          </ModalBody>
          <ModalFooter justify="center">
            <Button
              bem={{ shale_text: true }}
              onClick={() => {
                setConfirmModal({});
                modalRef.current.toggle(false);
              }}
            >
              Cancel
            </Button>
            <Button
              bem={confirmModalState.buttonText === 'Delete Tutorial' ? { red: true } : { blue: true }}
              onClick={() => {
                confirmModalState.action();
                modalRef.current.toggle(false);
              }}
            >
              {confirmModalState.buttonText}
            </Button>
          </ModalFooter>
        </Modal>
      </cmVariableContext.Provider>
    </PermissionContext.Provider>
  );
}

Tutorials.propTypes = {
  baseUrl: PropTypes.string,
  confirmationTarget: PropTypes.string,
  isAdmin: PropTypes.bool.isRequired,
  modalTarget: PropTypes.string,
  referenceEnabled: PropTypes.bool,
  slug: PropTypes.string,
  variables: PropTypes.shape({
    defaults: PropTypes.arrayOf(PropTypes.any),
    user: PropTypes.any,
  }),
};

Tutorials.defaultProps = {
  baseUrl: '',
  confirmationTarget: '#confirmation-root',
  isAdmin: false,
  modalTarget: '#modal-root',
  referenceEnabled: false,
  variables: {
    defaults: [],
    user: {},
  },
};
