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, { useState, useEffect } from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';

// Readme Libs
// import { supportedLanguages } from '@readme/oas-to-snippet';

// Components
import { Box, Button, Dropdown, Flex, Select } from '../../../../components';
import CodeEditor from '../../../CodeEditor';
import Method from '../../../../components/Method';
import Menu from '../../../../components/Menu';
import MenuDivider from '../../../../components/Menu/Divider';
import MenuHeader from '../../../../components/Menu/Header';
import MenuItem from '../../../../components/Menu/Item';

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

// Constants
import { StepSnippetProp, CodeOptionProp, EndpointProp } from '../../proptypes/tutorials';
import { ApiEndpointProp } from '../../proptypes/apiEndpoints';

// Permissions
import { PermissionContext } from '../..';

var LanguageDropdown = function LanguageDropdown(_ref) {
  var languageOpts = _ref.languageOpts,
      index = _ref.index,
      props = _objectWithoutProperties(_ref, ['languageOpts', 'index']);

  var maxTabCount = 4;
  var defaultLang = 'c';

  var _useState = useState(defaultLang),
      language = _useState[0],
      setLanguage = _useState[1];

  var handleTabCreate = function handleTabCreate() {
    if (language) {
      props.handleTabCreate({ language: language });
      setLanguage(defaultLang);
    }
  };

  return React.createElement(
    React.Fragment,
    null,
    index < maxTabCount && React.createElement(
      Dropdown,
      { className: classes['TutorialEditor-Nav-Plus'] },
      React.createElement(
        Button,
        { bem: { white_text: true } },
        React.createElement('i', { className: 'fa fa-plus-circle' })
      ),
      React.createElement(
        Box,
        { bem: [['pop']], style: { padding: 0 } },
        React.createElement(
          Menu,
          null,
          React.createElement(
            MenuItem,
            { TagName: 'div' },
            React.createElement(Select, { onChange: function onChange(e) {
                return setLanguage(e.target.value);
              }, options: languageOpts, size: 'sm', value: language })
          ),
          React.createElement(MenuDivider, null),
          React.createElement(
            MenuItem,
            { color: 'blue', onClick: handleTabCreate },
            'Create Tab'
          )
        )
      )
    )
  );
};

LanguageDropdown.propTypes = process.env.NODE_ENV !== "production" ? {
  handleTabCreate: PropTypes.func,
  index: PropTypes.number,
  languageOpts: PropTypes.arrayOf(PropTypes.shape({
    label: PropTypes.string,
    value: PropTypes.string
  }))
} : {};

var SnippetLanguageMenu = function SnippetLanguageMenu(_ref2) {
  var codeOptions = _ref2.codeOptions,
      languageOpts = _ref2.languageOpts,
      readOnly = _ref2.readOnly,
      setSelectedTab = _ref2.setSelectedTab,
      selectedTab = _ref2.selectedTab,
      props = _objectWithoutProperties(_ref2, ['codeOptions', 'languageOpts', 'readOnly', 'setSelectedTab', 'selectedTab']);

  var handleTabCreate = function handleTabCreate(_ref3) {
    var language = _ref3.language;

    // Basic scaffold for a new tab
    props.handleTabCreate({
      code: '',
      language: language,
      name: '' + language.charAt(0).toUpperCase() + language.slice(1)
    });
  };

  var tutorialTabClasses = function tutorialTabClasses(index) {
    return [classes['TutorialEditor-Nav-Tab'], index === selectedTab && classes['TutorialEditor-Nav-Tab_active']].filter(function (e) {
      return e;
    }).join(' ');
  };

  return React.createElement(
    Flex,
    null,
    codeOptions && codeOptions.map(function (opt, index) {
      return React.createElement(
        Button,
        {
          key: index,
          bem: { white_text: true },
          className: '' + tutorialTabClasses(index),
          onClick: function onClick() {
            return setSelectedTab(index);
          }
        },
        opt.name
      );
    }),
    !readOnly && React.createElement(LanguageDropdown, {
      handleTabCreate: handleTabCreate,
      index: codeOptions.length - 1,
      languageOpts: languageOpts
    })
  );
};

SnippetLanguageMenu.propTypes = process.env.NODE_ENV !== "production" ? {
  codeOptions: PropTypes.arrayOf(CodeOptionProp),
  handleTabCreate: PropTypes.func,
  languageOpts: PropTypes.arrayOf(PropTypes.shape({
    label: PropTypes.string,
    value: PropTypes.string
  })),
  readOnly: PropTypes.bool,
  selectedTab: PropTypes.number,
  setSelectedTab: PropTypes.func
} : {};

var EndpointSelector = function EndpointSelector(_ref4) {
  var baseUrl = _ref4.baseUrl,
      endpoints = _ref4.endpoints,
      codeOptions = _ref4.codeOptions,
      selectedEndpoint = _ref4.selectedEndpoint,
      readOnly = _ref4.readOnly,
      handleSnippetSelection = _ref4.handleSnippetSelection,
      clearSnippetSelection = _ref4.clearSnippetSelection;
  return React.createElement(
    Dropdown,
    { justify: 'right' },
    React.createElement(
      Button,
      _extends({
        bem: { white_text: true },
        className: classes['TutorialEditor-Nav-Button'],
        title: selectedEndpoint && selectedEndpoint.title || ''
      }, readOnly && selectedEndpoint && selectedEndpoint.slug && {
        href: baseUrl + '/reference-link/' + selectedEndpoint.slug,
        rel: 'noopener noreferrer',
        target: '_blank'
      }),
      selectedEndpoint && selectedEndpoint.method && React.createElement(Method, { type: selectedEndpoint.method.toLowerCase() }),
      React.createElement(
        'span',
        { className: classes['TutorialEditor-Nav-Button-Text'] },
        selectedEndpoint && selectedEndpoint.title || 'Reference'
      ),
      !readOnly && React.createElement('i', { className: 'fa fa-chevron-down' }),
      readOnly && selectedEndpoint && selectedEndpoint.slug && React.createElement('i', { className: ['fa fa-arrow-circle-up', classes['TutorialEditor-Nav-Button-Link-Icon']].join(' ') })
    ),
    !readOnly && React.createElement(
      Box,
      { bem: [['pop']], className: classes['TutorialEditor-Nav-Menu'] },
      React.createElement(
        Menu,
        null,
        selectedEndpoint && selectedEndpoint.title && React.createElement(
          React.Fragment,
          null,
          React.createElement(
            MenuHeader,
            null,
            selectedEndpoint.title
          ),
          React.createElement(
            MenuItem,
            { color: 'red', onClick: clearSnippetSelection },
            'Clear Selection'
          ),
          React.createElement(MenuDivider, null)
        ),
        React.createElement(
          MenuHeader,
          null,
          'API Definitions'
        ),
        endpoints && endpoints.map(function (endpoint, index) {
          return React.createElement(
            MenuItem,
            { key: 'tutorial-endpoint-group-' + index, openAt: 'left', title: endpoint.title },
            endpoint.title,
            React.createElement(
              Menu,
              null,
              React.createElement(
                MenuHeader,
                null,
                endpoint.title
              ),
              endpoint.children.map(function (child, idx) {
                return React.createElement(
                  MenuItem,
                  {
                    key: 'tutorial-endpoint-opt-' + idx,
                    onClick: function onClick() {
                      return handleSnippetSelection({ page: child, codeOptions: codeOptions });
                    },
                    title: child.title
                  },
                  React.createElement(
                    React.Fragment,
                    null,
                    React.createElement(Method, {
                      className: classes['TutorialEditor-Nav-Menu-Method'],
                      type: child.api.method.toLowerCase(),
                      width: 40
                    }),
                    React.createElement(
                      'span',
                      { className: classes['TutorialEditor-Nav-Menu-Text'] },
                      child.title
                    )
                  )
                );
              })
            )
          );
        })
      )
    )
  );
};

EndpointSelector.propTypes = process.env.NODE_ENV !== "production" ? {
  baseUrl: PropTypes.string,
  clearSnippetSelection: PropTypes.func,
  codeOptions: PropTypes.arrayOf(CodeOptionProp),
  endpoints: PropTypes.arrayOf(ApiEndpointProp),
  handleSnippetSelection: PropTypes.func,
  readOnly: PropTypes.bool,
  selectedEndpoint: EndpointProp
} : {};

var TabControls = function TabControls(_ref5) {
  var codeOption = _ref5.codeOption,
      selectedLines = _ref5.selectedLines,
      languageOpts = _ref5.languageOpts,
      selectedTab = _ref5.selectedTab,
      isOnlyTab = _ref5.isOnlyTab,
      handleLineUpdate = _ref5.handleLineUpdate,
      handleTabUpdate = _ref5.handleTabUpdate,
      handleTabDelete = _ref5.handleTabDelete;

  var lineNumberRegex = /^[0-9,-]+$/;
  var maxLength = 20;

  var handleLineInput = function handleLineInput(event) {
    var value = event.target.value;


    if (!value || lineNumberRegex.test(value)) {
      handleLineUpdate(value);
    }
  };

  var handleNameInput = function handleNameInput(event, key) {
    var value = event.target.value;

    if (value.length >= maxLength) event.target.value = value.slice(0, maxLength);
    if (value.length > 0) handleTabUpdate(event, key);
  };

  return React.createElement(
    'div',
    { className: classes['TutorialEditor-Controls'] },
    React.createElement(
      'label',
      {
        className: [classes['TutorialEditor-Controls-ControlWrapper'], classes['TutorialEditor-Controls-ControlWrapper_select']].join(' ')
      },
      React.createElement(
        'span',
        null,
        'Language'
      ),
      React.createElement(
        'select',
        {
          className: classes['TutorialEditor-Controls-ControlWrapper-Select'],
          onChange: function onChange(e) {
            return handleTabUpdate(e, 'language');
          },
          value: codeOption.language
        },
        languageOpts.map(function (_ref6, idx) {
          var value = _ref6.value,
              label = _ref6.label;
          return React.createElement(
            'option',
            { key: 'tab-control-language-' + idx, value: value },
            label
          );
        })
      )
    ),
    React.createElement(
      'label',
      { className: classes['TutorialEditor-Controls-ControlWrapper'] },
      React.createElement(
        'span',
        null,
        'Highlight'
      ),
      React.createElement('input', {
        className: classes['TutorialEditor-Controls-ControlWrapper-Input'],
        onChange: handleLineInput,
        placeholder: '1,4,7-9',
        value: selectedLines
      }),
      React.createElement('i', {
        className: ['fa fa-question', classes['TutorialEditor-Controls-ControlWrapper-Tooltip']].join(' '),
        'data-tooltip': 'Highlight multiple lines with commas and hyphens',
        'data-tooltip-position': 'right'
      })
    ),
    React.createElement(
      'label',
      { className: classes['TutorialEditor-Controls-ControlWrapper'] },
      React.createElement(
        'span',
        null,
        'Name'
      ),
      React.createElement('input', {
        className: classes['TutorialEditor-Controls-ControlWrapper-Input'],
        maxLength: maxLength,
        onChange: function onChange(e) {
          return handleNameInput(e, 'name');
        },
        value: codeOption.name
      })
    ),
    React.createElement(
      'button',
      {
        className: classes['TutorialEditor-Controls-Delete'],
        'data-tooltip': isOnlyTab ? 'Must have at least one tab' : '',
        'data-tooltip-position': 'left',
        disabled: isOnlyTab,
        onClick: function onClick() {
          return handleTabDelete(selectedTab);
        },
        type: 'button'
      },
      'Delete Tab'
    )
  );
};

TabControls.propTypes = process.env.NODE_ENV !== "production" ? {
  codeOption: CodeOptionProp,
  handleLineUpdate: PropTypes.func,
  handleTabDelete: PropTypes.func,
  handleTabUpdate: PropTypes.func,
  isOnlyTab: PropTypes.bool,
  languageOpts: PropTypes.arrayOf(PropTypes.shape({
    label: PropTypes.string,
    value: PropTypes.string
  })),
  selectedLines: PropTypes.string,
  selectedTab: PropTypes.number
} : {};

export default function TutorialEditor(_ref7) {
  var baseUrl = _ref7.baseUrl,
      snippet = _ref7.snippet,
      endpoints = _ref7.endpoints,
      lineNumbers = _ref7.lineNumbers,
      referenceEnabled = _ref7.referenceEnabled,
      selectedTab = _ref7.selectedTab,
      setSelectedTab = _ref7.setSelectedTab,
      handleSnippetSelection = _ref7.handleSnippetSelection,
      clearSnippetSelection = _ref7.clearSnippetSelection,
      updateStep = _ref7.updateStep,
      updateSnippet = _ref7.updateSnippet,
      props = _objectWithoutProperties(_ref7, ['baseUrl', 'snippet', 'endpoints', 'lineNumbers', 'referenceEnabled', 'selectedTab', 'setSelectedTab', 'handleSnippetSelection', 'clearSnippetSelection', 'updateStep', 'updateSnippet']);

  var _useState2 = useState(null),
      editorInstance = _useState2[0],
      setEditorInstance = _useState2[1];

  var _useState3 = useState(''),
      setLineNumbers = _useState3[1];

  var codeOptions = snippet.codeOptions,
      endpoint = snippet.endpoint;

  // TODO resolve module build issues for @readme/oas-to-snippet

  var languageOpts = [{ value: 'c', label: 'c' }, { value: 'node', label: 'node' }, { value: 'shell', label: 'curl' }, { value: 'python', label: 'python' }, { value: 'php', label: 'php' }];
  // const languageOpts = Object.keys(supportedLanguages).map(key => {
  //   return { value: key, label: key };
  // });

  // Converting between human readable `1, 2-5` to codemirror selection syntax
  var spreadLineNumbers = function spreadLineNumbers(ranges) {
    return ranges.split(',').map(function (range) {
      var _range$split = range.split('-'),
          anchor = _range$split[0],
          head = _range$split[1];

      var end = head || anchor ? parseInt(head || anchor, 10) : 0;
      var start = parseInt(anchor || 0, 10) - 1;

      return [{ ch: 0, line: start }, { ch: 0, line: end }];
    });
  };
  // Get the defined dimensions based on the first selected range
  // to programmatically scroll. This is necessary because codemirror likes to put
  // a margin buffer in their component
  var getEditorDimensions = function getEditorDimensions(editor, range) {
    var editorHeight = editor.getWrapperElement().parentNode.parentNode.offsetHeight;
    var lineHeight = 15;
    var start = range[0],
        end = range[1];


    var rangeHeight = (end.line - start.line) * lineHeight;
    var editorCenter = start.line * lineHeight - editorHeight / 2 - lineHeight / 2;

    // if there’s a range greater than one line
    if (rangeHeight > 15) {
      editorCenter += rangeHeight / 2;
      // if the range is larger than the editor
      if (rangeHeight > editorHeight) editorCenter = start.line * lineHeight - lineHeight;
    }

    return { editorHeight: editorHeight, editorCenter: editorCenter };
  };

  var markEditorInstance = function markEditorInstance(editor, lines) {
    // Clear existing style tags from our editor instance
    editor.getAllMarks().forEach(function (mark) {
      return mark.clear();
    });

    if (lines) {
      var ranges = spreadLineNumbers(lines);
      // Mark new ranges with classname
      ranges.forEach(function (_ref8) {
        var anchor = _ref8[0],
            head = _ref8[1];
        return editor.getDoc().markText(anchor, head, { className: 'CodeEditor-Highlight', addToHistory: true });
      });
      // Scroll to the first range so that code is in viewport

      var _getEditorDimensions = getEditorDimensions(editor, ranges[0]),
          editorHeight = _getEditorDimensions.editorHeight,
          editorCenter = _getEditorDimensions.editorCenter;

      editor.setSize('100%', editorHeight);
      editor.scrollTo(0, editorCenter);
    }
  };

  // Editor user interaction marking
  // Called when lineNumbers is updated (via input or step/tab change)
  useEffect(function () {
    var newLines = lineNumbers[selectedTab];
    if (editorInstance) {
      setLineNumbers(function (prevLines) {
        if (newLines === prevLines) return prevLines;
        setTimeout(function () {
          return markEditorInstance(editorInstance, newLines);
        });
        return newLines;
      });
    }
  });

  // getCode() is called when two conditions are fulfilled:
  // 1. When a snippet is already selected and assigned to the tutorial and a new tab is created
  // 2. When we create a new step
  // getCode will retrieve a code string and place it within the tab's target index
  var getCode = function getCode(language, index) {
    var page = snippet.endpoint.page;

    var pages = endpoints.reduce(function (arr, val) {
      return arr.concat(val.children);
    }, []);
    var foundPage = pages.find(function (_ref9) {
      var _id = _ref9._id;
      return _id === page;
    });

    if (foundPage) props.getCode({ page: foundPage, language: language, index: index });
  };

  var handleTabCreate = function handleTabCreate(codeOption) {
    lineNumbers.push('');
    updateStep({ lineNumbers: lineNumbers });

    codeOptions.push(codeOption);
    updateSnippet({ codeOptions: codeOptions });

    setSelectedTab(codeOptions.length - 1);
    getCode(codeOption.language, snippet.codeOptions.length - 1);
  };

  var handleTabUpdate = function handleTabUpdate(event, key) {
    codeOptions[selectedTab][key] = event.target.value;
    updateSnippet({ codeOptions: codeOptions });
  };

  var handleTabDelete = function handleTabDelete(index) {
    lineNumbers.splice(index, 1);
    updateStep({ lineNumbers: lineNumbers });

    codeOptions.splice(index, 1);
    updateSnippet({ codeOptions: codeOptions });

    setSelectedTab(0);
  };

  var handleLineUpdate = function handleLineUpdate(value) {
    lineNumbers[selectedTab] = value;
    updateStep({ lineNumbers: lineNumbers });
  };

  var handleCodeChange = function handleCodeChange(_ref10, code, readOnly) {
    var origin = _ref10.origin;

    if (['+input', 'paste', '+delete'].includes(origin) && !readOnly) {
      codeOptions[selectedTab].code = code;
      updateSnippet({ codeOptions: codeOptions });
    }
  };

  var checkCodeChange = process.env.NODE_ENV === 'test' ? handleCodeChange : _.debounce(handleCodeChange, 300);

  return React.createElement(
    PermissionContext.Consumer,
    null,
    function (readOnly) {
      return React.createElement(
        React.Fragment,
        null,
        React.createElement(
          Flex,
          { align: 'center', className: classes['TutorialEditor-Nav'], justify: 'between', tag: 'nav' },
          React.createElement(SnippetLanguageMenu, {
            codeOptions: codeOptions,
            handleTabCreate: handleTabCreate,
            languageOpts: languageOpts,
            readOnly: readOnly,
            selectedTab: selectedTab,
            setSelectedTab: setSelectedTab
          }),
          referenceEnabled && (readOnly || endpoints.length > 0) && React.createElement(EndpointSelector, {
            baseUrl: baseUrl,
            clearSnippetSelection: clearSnippetSelection,
            codeOptions: snippet.codeOptions,
            endpoints: endpoints,
            handleSnippetSelection: handleSnippetSelection,
            readOnly: readOnly,
            selectedEndpoint: endpoint
          })
        ),
        React.createElement(CodeEditor, {
          autoScroll: true,
          className: 'CodeEditor-Input ' + (readOnly && 'CodeEditor-Input_readonly' || ''),
          code: codeOptions[selectedTab].code,
          editorDidMount: setEditorInstance,
          lang: codeOptions[selectedTab].language,
          onChange: function onChange(editor, data, code) {
            return checkCodeChange(data, code, readOnly);
          },
          options: { readOnly: readOnly ? 'nocursor' : false }
        }),
        !readOnly && React.createElement(TabControls, {
          codeOption: codeOptions[selectedTab],
          handleLineUpdate: handleLineUpdate,
          handleTabDelete: handleTabDelete,
          handleTabUpdate: handleTabUpdate,
          isOnlyTab: codeOptions.length === 1,
          languageOpts: languageOpts,
          selectedLines: lineNumbers[selectedTab],
          selectedTab: selectedTab
        })
      );
    }
  );
}

TutorialEditor.propTypes = process.env.NODE_ENV !== "production" ? {
  baseUrl: PropTypes.string,
  clearSnippetSelection: PropTypes.func,
  endpoints: PropTypes.arrayOf(ApiEndpointProp),
  getCode: PropTypes.func,
  handleSnippetSelection: PropTypes.func,
  lineNumbers: PropTypes.arrayOf(PropTypes.string),
  referenceEnabled: PropTypes.bool,
  selectedTab: PropTypes.number,
  setSelectedTab: PropTypes.func,
  snippet: StepSnippetProp,
  updateSnippet: PropTypes.func,
  updateStep: PropTypes.func
} : {};