var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };

function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }

// 3rd-Party Libraries
import React, { useRef, useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

// Components
import { Button, Flex, Modal, Title, Notification } from '../../components';
import { TutorialCard, TutorialObstacle, TutorialTile } from './..';
import TutorialEditor from './components/TutorialEditor';
import TutorialStep from './components/TutorialStep';
import TutorialStepNav from './components/TutorialStepNav';
import TutorialResponse from './components/TutorialResponse';
import TutorialReview from './components/TutorialReview';

// Constants
import { DEFAULT_TUTORIAL, DEFAULT_STEP, DEFAULT_SNIPPET } from './constants/stepDefaults';
import { TutorialProp } from './proptypes/tutorials';

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

// Style
import classes from './style.module.scss';

// Permissions
export var PermissionContext = React.createContext(true);

export default function TutorialModal(_ref) {
  var action = _ref.action,
      baseUrl = _ref.baseUrl,
      target = _ref.target,
      tutorial = _ref.tutorial,
      closeTutorialModal = _ref.closeTutorialModal,
      requestDataRefresh = _ref.requestDataRefresh,
      referenceEnabled = _ref.referenceEnabled,
      props = _objectWithoutProperties(_ref, ['action', 'baseUrl', 'target', 'tutorial', 'closeTutorialModal', 'requestDataRefresh', 'referenceEnabled']);

  var modalRef = React.createRef();
  var tutorialForm = useRef(false);
  // Modal interaction state

  var _useState = useState(props.open),
      open = _useState[0],
      setOpenState = _useState[1];

  var _useState2 = useState(0),
      selectedStep = _useState2[0],
      setSelectedStep = _useState2[1];

  var _useState3 = useState(0),
      selectedTab = _useState3[0],
      setSelectedTab = _useState3[1];

  var _useState4 = useState(false),
      tutorialReview = _useState4[0],
      setTutorialReview = _useState4[1];

  var _useState5 = useState(false),
      tutorialCreated = _useState5[0],
      setTutorialCreated = _useState5[1];
  // Modal data state


  var _useState6 = useState(tutorial.steps),
      steps = _useState6[0],
      setSteps = _useState6[1];

  var _useState7 = useState(tutorial.snippet),
      snippet = _useState7[0],
      setSnippet = _useState7[1];

  var _useState8 = useState(tutorial),
      tutorialShell = _useState8[0],
      setTutorialShell = _useState8[1];
  // Indirect request handling (via API)


  var _useState9 = useState([]),
      endpoints = _useState9[0],
      setEndpoints = _useState9[1];

  var _useState10 = useState(null),
      saved = _useState10[0],
      setSaved = _useState10[1];

  var _useReadmeApi = useReadmeApi(baseUrl),
      response = _useReadmeApi.response,
      error = _useReadmeApi.error,
      setError = _useReadmeApi.setError,
      initRequest = _useReadmeApi.initRequest;

  // Applying outer props to modal component ref


  useEffect(function () {
    if (props.open !== open) {
      setOpenState(props.open);
      modalRef.current.toggle(props.open);

      if (props.open) {
        setTutorialCreated(false);
        setTutorialReview(false);
      }
    }
  });

  /* Start: Applying Hub2 API request data to state */
  useEffect(function () {
    if (action !== 'View' && !endpoints.length) ApiActions.getEndpoints(initRequest);
  }, [open]);

  useEffect(function () {
    if (response.endpoints) setEndpoints(response.endpoints);
  }, [response.endpoints]);

  useEffect(function () {
    if (response.tutorial) {
      setTutorialShell(_extends({}, response.tutorial));
      requestDataRefresh();
      setError(null);
      // Notifications -> Error/Success or Published Successfully
      // If in creation flow, show success modal
      if (action === 'Create' && response.tutorial.published) {
        setTutorialCreated(true);
        setTutorialReview(false);
        // Otherwise, flash notification
      } else {
        setSaved('Successfully Saved!');
        setTimeout(function () {
          return setSaved(null);
        }, 2500);
      }
    }
  }, [response.tutorial]);

  useEffect(function () {
    if (response.snippet) setSnippet(response.snippet);
  }, [response.snippet]);

  useEffect(function () {
    if (response.codeString) {
      setSnippet(function (prevSnippet) {
        var _response$codeString = response.codeString,
            code = _response$codeString.code,
            index = _response$codeString.index;

        prevSnippet.codeOptions[index].code = code;
        return _extends({}, prevSnippet);
      });
    }
  }, [response.codeString]);
  /* End: Applying Hub2 API request data to state */

  /* Start: Applying new prop data to state */
  useEffect(function () {
    setSelectedStep(0);
    tutorial.steps[0].isOpen = true;
    setSteps([].concat(tutorial.steps));
  }, [tutorial.steps]);

  useEffect(function () {
    setSelectedTab(0);
    setSnippet(_extends({}, tutorial.snippet));
  }, [tutorial.snippet]);

  useEffect(function () {
    setTutorialShell(_extends({}, tutorial));
  }, [tutorial]);
  /* End: Applying new prop data to state */

  /* Start Syncing States */
  // Syncing Step and Snippet states to parent tutorial
  useEffect(function () {
    setTutorialShell(function (prevTutorial) {
      return _extends({}, prevTutorial, {
        stepCount: steps.length,
        steps: steps,
        snippet: snippet
      });
    });
  }, [steps, snippet]);
  // Syncing steps[n].lineNumbers with snippet.codeOptions
  // These are disjointed arrays which can be referenced in ./propTypes/tutorials
  // Which deal with highly related, but disparate data. We need to ensure
  // that they have the same number of elements. We can do that by reading from `codeOptions`.
  useEffect(function () {
    var tabCount = snippet.codeOptions.length;

    setSteps(function (prevSteps) {
      prevSteps.forEach(function (_ref2) {
        var lineNumbers = _ref2.lineNumbers;

        if (lineNumbers.length > tabCount) lineNumbers.splice(selectedTab, 1);
        if (lineNumbers.length < tabCount) lineNumbers.push('');
      });
      return prevSteps;
    });
  }, [snippet.codeOptions.length]);
  /* End Syncing States */

  var navStep = function navStep(direction) {
    setSteps(function (prevSteps) {
      var newSelection = selectedStep + direction;

      prevSteps[selectedStep].isOpen = false;
      prevSteps[newSelection].isOpen = true;
      setSelectedStep(newSelection);

      return [].concat(prevSteps);
    });
  };

  var validateStep = function validateStep() {
    return tutorialForm.current.reportValidity();
  };

  var selectStep = function selectStep(index) {
    if (validateStep()) {
      setSelectedStep(index);
      setSteps(function (prevSteps) {
        var step = prevSteps[index];
        var previousStep = prevSteps.find(function (s) {
          return s.isOpen;
        });

        previousStep.isOpen = false;
        step.isOpen = true;

        return [].concat(prevSteps);
      });
    }
  };

  var shiftStepOrder = function shiftStepOrder(index, direction) {
    setSteps(function (prevSteps) {
      var swap = index + direction;
      // https://stackoverflow.com/a/872317
      // Acts a means to swap indices without assigning to a temp variable
      var _ref3 = [prevSteps[swap], prevSteps[index]];
      prevSteps[index] = _ref3[0];
      prevSteps[swap] = _ref3[1];


      var updatedSelection = _.findIndex(steps, function (s) {
        return s.isOpen;
      });
      setSelectedStep(updatedSelection);

      return [].concat(prevSteps);
    });
  };

  var createStep = function createStep() {
    if (validateStep()) {
      setSelectedStep(steps.length);
      setSteps(function (prevSteps) {
        var prevOpen = prevSteps.find(function (s) {
          return s.isOpen;
        });
        prevOpen.isOpen = false;

        return [].concat(prevSteps, [_extends({}, _.cloneDeep(DEFAULT_STEP), {
          lineNumbers: snippet.codeOptions.map(function () {
            return '';
          })
        })]);
      });
    }
  };

  var updateStep = function updateStep(data) {
    var _Object$entries$ = Object.entries(data)[0],
        key = _Object$entries$[0],
        value = _Object$entries$[1];


    setSteps(function (prevSteps) {
      var step = prevSteps[selectedStep];
      step[key] = value;
      return [].concat(prevSteps);
    });
  };

  var deleteStep = function deleteStep(index) {
    setSelectedStep(0);
    setSteps(function (prevSteps) {
      prevSteps.splice(index, 1);
      prevSteps[0].isOpen = true;

      return [].concat(prevSteps);
    });
  };

  var updateSnippet = function updateSnippet(data) {
    setSnippet(function (prevSnippet) {
      return _extends({}, prevSnippet, data);
    });
  };

  var clearSnippetSelection = function clearSnippetSelection() {
    setSelectedTab(0);
    setSnippet(_.cloneDeep(DEFAULT_SNIPPET));
  };

  var updateTutorial = function updateTutorial(data) {
    setTutorialShell(function (prevShell) {
      return _extends({}, prevShell, data);
    });
  };

  var upsertTutorial = function upsertTutorial(published) {
    if (validateStep()) {
      var payload = _extends({}, tutorialShell, {
        published: published
      });

      if (tutorialShell._id) return ApiActions.updateTutorial(initRequest, payload);
      return ApiActions.createTutorial(initRequest, payload);
    }
    return false;
  };

  return React.createElement(
    PermissionContext.Provider,
    { value: action === 'View' },
    React.createElement(
      Modal,
      {
        ref: modalRef,
        className: [classes.TutorialModal, tutorialCreated && classes.TutorialModal_created].join(' '),
        onClose: closeTutorialModal,
        open: !!open,
        target: target
      },
      !tutorialReview && !tutorialCreated && React.createElement(
        React.Fragment,
        null,
        React.createElement(
          Flex,
          { align: 'center', className: classes['TutorialModal-Nav'], justify: 'between' },
          React.createElement(
            Title,
            { className: classes['TutorialStepNav-Title'], level: 4 },
            tutorialShell.title
          ),
          React.createElement(
            Flex,
            { align: 'center' },
            action !== 'View' && React.createElement(
              React.Fragment,
              null,
              React.createElement(
                Button,
                {
                  bem: { slate: true },
                  form: 'tutorialForm',
                  onClick: function onClick(e) {
                    e.preventDefault();
                    upsertTutorial(false);
                  },
                  type: 'submit'
                },
                'Save'
              ),
              React.createElement(
                Button,
                {
                  form: 'tutorialForm',
                  onClick: function onClick(e) {
                    e.preventDefault();
                    if (validateStep()) setTutorialReview(true);
                  },
                  type: 'submit'
                },
                'Review'
              )
            ),
            React.createElement(
              'button',
              { className: classes['TutorialModal-Nav-Close'], onClick: closeTutorialModal, type: 'button' },
              React.createElement('i', { className: 'icon icon-readme-remove' })
            )
          )
        ),
        React.createElement(
          'div',
          { className: classes['TutorialModal-Row'] },
          React.createElement(
            'form',
            {
              ref: tutorialForm,
              className: [classes['TutorialModal-Col'], classes['TutorialModal-Col_steps']].join(' '),
              id: 'tutorialForm'
            },
            React.createElement(
              TutorialStepNav,
              { createStep: createStep },
              steps && steps.map(function (step, index) {
                return React.createElement(TutorialStep, {
                  key: 'tutorial-step-' + index,
                  action: action,
                  deleteStep: deleteStep,
                  handleClick: function handleClick() {
                    return selectStep(index);
                  },
                  index: index,
                  lastIndex: steps.length - 1,
                  navStep: navStep,
                  shiftOrder: function shiftOrder(direction) {
                    return shiftStepOrder(index, direction);
                  },
                  step: step,
                  updateStep: updateStep
                });
              })
            )
          ),
          React.createElement(
            'div',
            {
              className: [classes['TutorialModal-Col'], !(action !== 'View' || action === 'View' && !!tutorialShell.response.length) && classes['TutorialModal-Col_singleEditor']].join(' ')
            },
            React.createElement(TutorialEditor, {
              key: 'tutorial-editor-' + selectedStep,
              baseUrl: baseUrl,
              clearSnippetSelection: clearSnippetSelection,
              endpoints: endpoints,
              getCode: function getCode(data) {
                return ApiActions.getCodeString(initRequest, data);
              },
              handleSnippetSelection: function handleSnippetSelection(data) {
                return ApiActions.getCodeSnippets(initRequest, data);
              },
              lineNumbers: steps[selectedStep].lineNumbers,
              referenceEnabled: referenceEnabled,
              selectedTab: selectedTab,
              setSelectedTab: setSelectedTab,
              snippet: snippet,
              updateSnippet: updateSnippet,
              updateStep: updateStep
            }),
            (action !== 'View' || action === 'View' && tutorialShell.response && !!tutorialShell.response.length) && React.createElement(TutorialResponse, {
              key: 'tutorial-result-' + selectedStep,
              response: tutorialShell.response,
              updateTutorial: updateTutorial
            })
          )
        )
      ),
      tutorialReview && React.createElement(
        React.Fragment,
        null,
        React.createElement(
          Flex,
          { align: 'center', className: classes['TutorialModal-Nav'], justify: 'between' },
          React.createElement(
            Flex,
            { align: 'center', className: classes['TutorialModal-Nav-Left'] },
            React.createElement(
              'button',
              {
                className: classes['TutorialModal-Nav-Back'],
                onClick: function onClick() {
                  return setTutorialReview(false);
                },
                type: 'button'
              },
              React.createElement('i', { className: 'fa fa-chevron-left' })
            ),
            React.createElement(
              Title,
              { className: classes['TutorialStepNav-Title'], level: 4, title: tutorial.title },
              tutorialShell.title
            )
          ),
          React.createElement(
            Flex,
            { align: 'center' },
            action === 'Create' && React.createElement(
              React.Fragment,
              null,
              React.createElement(
                Button,
                {
                  bem: { slate: true },
                  form: 'tutorialForm',
                  onClick: function onClick(e) {
                    e.preventDefault();
                    upsertTutorial(false);
                  },
                  type: 'submit'
                },
                'Save'
              ),
              React.createElement(
                Button,
                {
                  form: 'tutorialForm',
                  onClick: function onClick(e) {
                    e.preventDefault();
                    upsertTutorial(true);
                  },
                  type: 'submit'
                },
                'Publish'
              )
            ),
            action === 'Edit' && React.createElement(
              Button,
              { onClick: function onClick() {
                  return upsertTutorial();
                } },
              'Save'
            ),
            React.createElement(
              'button',
              { className: classes['TutorialModal-Nav-Close'], onClick: closeTutorialModal, type: 'button' },
              React.createElement('i', { className: 'icon icon-readme-remove' })
            )
          )
        ),
        React.createElement(
          'div',
          { className: classes['TutorialModal-Row'] },
          React.createElement(
            'form',
            {
              ref: tutorialForm,
              className: [classes['TutorialModal-Col'], classes['TutorialModal-Col_review']].join(' '),
              id: 'tutorialForm'
            },
            React.createElement(TutorialReview, { endpoints: endpoints, tutorial: tutorialShell, updateTutorial: updateTutorial })
          ),
          React.createElement(
            'div',
            { className: [classes['TutorialModal-Col'], classes['TutorialModal-Col_review']].join(' ') },
            React.createElement(
              Flex,
              { align: 'center', className: classes['TutorialModal-Col-Wrapper'], justify: 'center', layout: 'col' },
              React.createElement(TutorialCard, { tutorial: tutorialShell, tutorialReview: tutorialReview }),
              React.createElement(
                'span',
                { className: classes['TutorialModal-Col-Wrapper-Caption'] },
                'Tutorial Page Preview'
              )
            ),
            React.createElement(
              Flex,
              { align: 'center', className: classes['TutorialModal-Col-Wrapper'], justify: 'center', layout: 'col' },
              React.createElement(TutorialTile, { tutorial: tutorialShell }),
              React.createElement(
                'span',
                { className: classes['TutorialModal-Col-Wrapper-Caption'] },
                'Guide/Reference Embed Preview'
              )
            )
          )
        )
      ),
      tutorialCreated && React.createElement(
        TutorialObstacle,
        {
          body: 'You can view and update your tutorial from the dedicated tutorial page.',
          className: classes['TutorialModal-Obstacle'],
          closeTutorialModal: closeTutorialModal,
          heading: 'You\u2019ve published a Tutorial!',
          tutorial: tutorialShell
        },
        React.createElement(
          Button,
          { onClick: closeTutorialModal },
          'View Tutorials'
        )
      ),
      action !== 'View' && error && React.createElement(
        Notification,
        { color: 'red', dismissible: true, handleClick: function handleClick() {
            return setError(null);
          }, position: 'top' },
        React.createElement(
          'p',
          null,
          error
        )
      ),
      action !== 'View' && saved && React.createElement(
        Notification,
        { color: 'green', position: 'top' },
        React.createElement(
          'p',
          null,
          saved
        )
      )
    )
  );
}

TutorialModal.propTypes = process.env.NODE_ENV !== "production" ? {
  action: PropTypes.oneOf(['Create', 'Edit', 'View']),
  baseUrl: PropTypes.string,
  closeTutorialModal: PropTypes.func,
  open: PropTypes.bool,
  referenceEnabled: PropTypes.bool,
  requestDataRefresh: PropTypes.func,
  target: PropTypes.string,
  tutorial: TutorialProp
} : {};

TutorialModal.defaultProps = {
  action: 'View',
  baseUrl: '',
  closeTutorialModal: function closeTutorialModal() {},
  open: false,
  referenceEnabled: false,
  requestDataRefresh: function requestDataRefresh() {},
  tutorial: _.cloneDeep(DEFAULT_TUTORIAL)
};