// 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 ModalBody from '@ui/components/Modal/Body';
import ModalFooter from '@ui/components/Modal/Footer';
import TutorialHero from './components/TutorialHero';
import TutorialCard from '@ui/compositions/TutorialCard';
import TutorialModal from '@ui/compositions/TutorialModal';
import TutorialObstacle from '@ui/compositions/TutorialObstacle';

// Constants
import { DEFAULT_TUTORIAL } from '@ui/compositions/TutorialModal/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') classes = require('./style.module.scss');

export const PermissionContext = React.createContext(false);

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}/tutorials/${pathSlug}` : `${baseUrl}/tutorials`;
      // eslint-disable-next-line no-restricted-globals
      history.pushState('', '', uri);
    }
  };

  const openTutorial = (action, id) => {
    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 = (id && id.toString()) || '';

      if (prevId !== newId && action === 'Create') {
        return { ...cloneDeep(DEFAULT_TUTORIAL) };
      } else if (prevId !== newId) {
        const tutorial = tutorials.find(tut => tut._id.toString() === newId);
        pushState(tutorial.slug);
        return { ...tutorial };
      }
      // 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 tutorial?`,
      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 Tutorial',
    });
  };

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

  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 tutorial?',
      body: 'Featuring an unpublished tutorial will publish it. Make sure it’s ready!',
      action: ApiActions.makeHero.bind(null, initRequest, { _id }),
      buttonText: 'Feature It!',
    });
  };

  return (
    <PermissionContext.Provider value={isAdmin}>
      <cmVariableContext.Provider value={props.variables}>
        {!initialLoad && !tutorials.length && (
          <TutorialObstacle
            body="Tutorials are task-driven guidance for your API. Try creating a new Tutorial for your users!"
            className={modalMeta.open && 'paused'}
            heading="Create a Tutorial to Get Started"
          >
            <Button onClick={() => openTutorial('Create')}>Create Tutorial</Button>
            <Button bem={{ shale: true }}>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>
        )}
        {isAdmin && (
          <div className={classes.TutorialToolbar}>
            <div
              data-tooltip={
                !tutorials.length ? 'The Tutorial view won’t be shown until you create your first tutorial.' : ''
              }
              data-tooltip-position="top"
            >
              <Toggle
                checked={moduleEnabled}
                disabled={!tutorials.length}
                label="Show Tutorials in Navigation"
                onChange={() => ApiActions.toggleModule(initRequest)}
                type="toggle"
              />
            </div>
            <Button
              bem={{ blue: true }}
              circular
              className={classes['TutorialToolbar-Button']}
              onClick={() => openTutorial('Create')}
            >
              Create Tutorial
            </Button>
          </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}
          endpointOnboarding={onboarding.endpoints}
          open={modalMeta.open}
          referenceEnabled={referenceEnabled}
          requestDataRefresh={() => getTutorials()}
          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,
};
