text: // @flow
  import * as React from 'react';
  import autobind from 'autobind-decorator';
  import Modal from '../base/modal';
  import ModalBody from '../base/modal-body';
  import ModalHeader from '../base/modal-header';
  import HelpTooltip from '../help-tooltip';
  import * as models from '../../../models';
  import DebouncedInput from '../base/debounced-input';
  import MarkdownEditor from '../markdown-editor';
  import * as db from '../../../common/database';
  import type { Workspace } from '../../../models/workspace';
  import type { Request } from '../../../models/request';
  
  type Props = {
    editorFontSize: number,
    editorIndentSize: number,
    editorKeyMap: string,
    editorLineWrapping: boolean,
    nunjucksPowerUserMode: boolean,
    isVariableUncovered: boolean,
    handleRender: Function,
    handleGetRenderContext: Function,
    workspaces: Array<Workspace>,
  };
  
  type State = {
    request: Request | GrpcRequest | null,
    showDescription: boolean,
    defaultPreviewMode: boolean,
    activeWorkspaceIdToCopyTo: string | null,
    workspace: Workspace | null,
    justCopied: boolean,
    justMoved: boolean,
  };
  
  type RequestSettingsModalOptions = {
    request: Request | GrpcRequest,
    forceEditMode: boolean,
  };
  
  @autobind
  class RequestSettingsModal extends React.PureComponent<Props, State> {
    modal: ?Modal;
    _editor: ?MarkdownEditor;
  
    constructor(props: Props) {
      super(props);
      this.state = {
        request: null,
        showDescription: false,
        defaultPreviewMode: false,
        activeWorkspaceIdToCopyTo: null,
        workspace: null,
        workspaces: [],
        justCopied: false,
        justMoved: false,
      };
    }
  
    _setModalRef(n: ?Modal) {
      this.modal = n;
    }
  
    _setEditorRef(n: ?MarkdownEditor) {
      this._editor = n;
    }
  
    async _updateRequestSettingBoolean(e: SyntheticEvent<HTMLInputElement>) {
      if (!this.state.request) {
        // Should never happen
        return;
      }
  
      const value = e.currentTarget.checked;
      const setting = e.currentTarget.name;
      const request = await models.request.update(this.state.request, {
        [setting]: value,
      });
      this.setState({ request });
    }
  
    async _updateRequestSettingString(e: SyntheticEvent<HTMLInputElement>) {
      if (!this.state.request) {
        // Should never happen
        return;
      }
  
      const value = e.currentTarget.value;
      const setting = e.currentTarget.name;
      const request = await models.request.update(this.state.request, {
        [setting]: value,
      });
      this.setState({ request });
    }
  
    async _handleNameChange(name: string) {
      if (!this.state.request) {
        return;
      }
      const request = await models.request.update(this.state.request, { name });
      this.setState({ request });
    }
  
    async _handleDescriptionChange(description: string) {
      if (!this.state.request) {
        return;
      }
      const request = await models.request.update(this.state.request, {
        description,
      });
      this.setState({ request, defaultPreviewMode: false });
    }
  
    _handleAddDescription() {
      this.setState({ showDescription: true });
    }
  
    _handleUpdateMoveCopyWorkspace(e: SyntheticEvent<HTMLSelectElement>) {
      const { value } = e.currentTarget;
      const workspaceId = value === '__NULL__' ? null : value;
      this.setState({ activeWorkspaceIdToCopyTo: workspaceId });
    }
  
    async _handleMoveToWorkspace() {
      const { activeWorkspaceIdToCopyTo, request } = this.state;
      if (!request || !activeWorkspaceIdToCopyTo) {
        return;
      }
  
      const workspace = await models.workspace.getById(activeWorkspaceIdToCopyTo);
      if (!workspace) {
        return;
      }
  
      await models.request.update(request, {
        metaSortKey: -1e9, // Move to top of sort order
        parentId: activeWorkspaceIdToCopyTo,
      });
  
      this.setState({ justMoved: true });
      setTimeout(() => {
        this.setState({ justMoved: false });
      }, 2000);
    }
  
    async _handleCopyToWorkspace() {
      const { activeWorkspaceIdToCopyTo, request } = this.state;
      if (!request || !activeWorkspaceIdToCopyTo) {
        return;
      }
  
      const workspace = await models.workspace.getById(activeWorkspaceIdToCopyTo);
      if (!workspace) {
        return;
      }
  
      const newRequest = await models.request.duplicate(request);
      await models.request.update(newRequest, {
        metaSortKey: -1e9, // Move to top of sort order
        name: request.name, // Because duplicate will add (Copy) suffix
        parentId: activeWorkspaceIdToCopyTo,
      });
  
      this.setState({ justCopied: true });
      setTimeout(() => {
        this.setState({ justCopied: false });
      }, 2000);
    }
  
    async show({ request, forceEditMode }: RequestSettingsModalOptions) {
      const { workspaces } = this.props;
  
      const hasDescription = !!request.description;
  
      // Find workspaces for use with moving workspace
      const ancestors = await db.withAncestors(request);
      const doc = ancestors.find(doc => doc.type === models.workspace.type);
      const workspaceId = doc ? doc._id : 'should-never-happen';
      const workspace = workspaces.find(w => w._id === workspaceId);
  
      this.setState(
        {
          request,
          workspace: workspace,
          activeWorkspaceIdToCopyTo: null,
          showDescription: forceEditMode || hasDescription,
          defaultPreviewMode: hasDescription && !forceEditMode,
        },
        () => {
          this.modal && this.modal.show();
  
          if (forceEditMode) {
            setTimeout(() => {
              this._editor && this._editor.focus();
            }, 400);
          }
        },
      );
    }
  
    hide() {
      this.modal && this.modal.hide();
    }
  
    renderCheckboxInput(setting: string) {
      const { request } = this.state;
      if (!request) {
        return;
      }
  
      return (
        <input
          type="checkbox"
          name={setting}
          checked={request[setting]}
          onChange={this._updateRequestSettingBoolean}
        />
      );
    }
  
    _renderRequestSettings(): React.Node {
      const { request } = this.state;
      if (!request || request.type === models.grpcRequest.type) {
        // GrpcRequests do not have any request settings (yet)
        // When the time comes, explore creating a standalone request settings modal for gRPC
        return;
      }
  
      return (
        <>
          <div className="pad-top pad-bottom">
            <div className="form-control form-control--thin">
              <label>
                Send cookies automatically
                {this.renderCheckboxInput('settingSendCookies')}
              </label>
            </div>
            <div className="form-control form-control--thin">
              <label>
                Store cookies automatically
                {this.renderCheckboxInput('settingStoreCookies')}
              </label>
            </div>
            <div className="form-control form-control--thin">
              <label>
                Automatically encode special characters in URL
                {this.renderCheckboxInput('settingEncodeUrl')}
                <HelpTooltip position="top" className="space-left">
                  Automatically encode special characters at send time (does not apply to query
                  parameters editor)
                </HelpTooltip>
              </label>
            </div>
            <div className="form-control form-control--thin">
              <label>
                Skip rendering of request body
                {this.renderCheckboxInput('settingDisableRenderRequestBody')}
                <HelpTooltip position="top" className="space-left">
                  Disable rendering of environment variables and tags for the request body
                </HelpTooltip>
              </label>
            </div>
            <div className="form-control form-control--thin">
              <label>
                Rebuild path dot sequences
                <HelpTooltip position="top" className="space-left">
                  This instructs libcurl to squash sequences of "/../" or "/./" that may exist in the
                  URL's path part and that is supposed to be removed according to RFC 3986 section
                  5.2.4
                </HelpTooltip>
                {this.renderCheckboxInput('settingRebuildPath')}
              </label>
            </div>
          </div>
          <div className="form-control form-control--outlined">
            <label>
              Follow redirects <span className="txt-sm faint italic">(overrides global setting)</span>
              <select
                defaultValue={this.state.request && this.state.request.settingFollowRedirects}
                name="settingFollowRedirects"
                onChange={this._updateRequestSettingString}>
                <option value={'global'}>Use global setting</option>
                <option value={'off'}>Don't follow redirects</option>
                <option value={'on'}>Follow redirects</option>
              </select>
            </label>
          </div>
        </>
      );
    }
  
    renderModalBody(): React.Node {
      const {
        editorLineWrapping,
        editorFontSize,
        editorIndentSize,
        editorKeyMap,
        handleRender,
        handleGetRenderContext,
        nunjucksPowerUserMode,
        isVariableUncovered,
        workspaces,
      } = this.props;
  
      const {
        showDescription,
        defaultPreviewMode,
        activeWorkspaceIdToCopyTo,
        justMoved,
        justCopied,
        workspace,
        request,
      } = this.state;
  
      if (!request) {
        return null;
      }
  
      return (
        <div>
          <div className="form-control form-control--outlined">
            <label>
              Name{' '}
              <span className="txt-sm faint italic">(also rename by double-clicking in sidebar)</span>
              <DebouncedInput
                delay={500}
                type="text"
                placeholder={request.url || 'My Request'}
                defaultValue={request.name}
                onChange={this._handleNameChange}
              />
            </label>
          </div>
          {showDescription ? (
            <MarkdownEditor
              ref={this._setEditorRef}
              className="margin-top"
              defaultPreviewMode={defaultPreviewMode}
              fontSize={editorFontSize}
              indentSize={editorIndentSize}
              keyMap={editorKeyMap}
              placeholder="Write a description"
              lineWrapping={editorLineWrapping}
              handleRender={handleRender}
              handleGetRenderContext={handleGetRenderContext}
              nunjucksPowerUserMode={nunjucksPowerUserMode}
              isVariableUncovered={isVariableUncovered}
              defaultValue={request.description}
              onChange={this._handleDescriptionChange}
            />
          ) : (
            <button
              onClick={this._handleAddDescription}
              className="btn btn--outlined btn--super-duper-compact">
              Add Description
            </button>
          )}
          {this._renderRequestSettings()}
          <hr />
          <div className="form-row">
            <div className="form-control form-control--outlined">
              <label>
                Move/Copy to Workspace
                <HelpTooltip position="top" className="space-left">
                  Copy or move the current request to a new workspace. It will be placed at the root
                  of the new workspace's folder structure.
                </HelpTooltip>
                <select
                  value={activeWorkspaceIdToCopyTo || '__NULL__'}
                  onChange={this._handleUpdateMoveCopyWorkspace}>
                  <option value="__NULL__">-- Select Workspace --</option>
                  {workspaces.map(w => {
                    if (workspace && workspace._id === w._id) {
                      return null;
                    }
  
                    return (
                      <option key={w._id} value={w._id}>
                        {w.name}
                      </option>
                    );
                  })}
                </select>
              </label>
            </div>
            <div className="form-control form-control--no-label width-auto">
              <button
                disabled={justCopied || !activeWorkspaceIdToCopyTo}
                className="btn btn--clicky"
                onClick={this._handleCopyToWorkspace}>
                {justCopied ? 'Copied!' : 'Copy'}
              </button>
            </div>
            <div className="form-control form-control--no-label width-auto">
              <button
                disabled={justMoved || !activeWorkspaceIdToCopyTo}
                className="btn btn--clicky"
                onClick={this._handleMoveToWorkspace}>
                {justMoved ? 'Moved!' : 'Move'}
              </button>
            </div>
          </div>
        </div>
      );
    }
  
    render() {
      const { request } = this.state;
      return (
        <Modal ref={this._setModalRef} freshState>
          <ModalHeader>
            Request Settings{' '}
            <span className="txt-sm selectable faint monospace">{request ? request._id : ''}</span>
          </ModalHeader>
          <ModalBody className="pad">{this.renderModalBody()}</ModalBody>
        </Modal>
      );
    }
  }
  
  export default RequestSettingsModal;
  