( function( wp ) {
  'use strict';

  if ( ! wp || ! wp.plugins || ! wp.editPost || ! wp.element || ! wp.components || ! wp.data || ! window.pdtContentVisibilityEditor ) {
    return;
  }

  var registerPlugin = wp.plugins.registerPlugin;
  var PluginDocumentSettingPanel = wp.editPost.PluginDocumentSettingPanel;
  var createElement = wp.element.createElement;
  var Fragment = wp.element.Fragment;
  var useEffect = wp.element.useEffect;
  var useRef = wp.element.useRef;
  var useSelect = wp.data.useSelect;
  var useDispatch = wp.data.useDispatch;
  var CheckboxControl = wp.components.CheckboxControl;
  var SelectControl = wp.components.SelectControl;
  var TextControl = wp.components.TextControl;
  var Notice = wp.components.Notice;

  var config = window.pdtContentVisibilityEditor;
  var keys = config.metaKeys || {};

  function toOptions( map ) {
    var options = [];

    Object.keys( map || {} ).forEach( function( key ) {
      options.push( { label: map[ key ], value: key } );
    } );

    return options;
  }

  function TinyMCEControl( props ) {
    var editorIdRef = useRef( 'pdt-content-visibility-message-editor' );
    var lastValueRef = useRef( props.value || '' );
    var textareaEventsBoundRef = useRef( false );
    var editorId = editorIdRef.current;

    useEffect( function() {
      if ( ! window.wp || ! window.wp.editor || 'function' !== typeof window.wp.editor.initialize ) {
        return undefined;
      }

      var textarea = document.getElementById( editorId );

      if ( ! textarea ) {
        return undefined;
      }

      function syncTextareaValue() {
        var field = document.getElementById( editorId );

        if ( ! field ) {
          return;
        }

        if ( field.value === lastValueRef.current ) {
          return;
        }

        lastValueRef.current = field.value;
        props.onChange( field.value );
      }

      window.wp.editor.initialize(
        editorId,
        {
          mediaButtons: false,
          quicktags: true,
          tinymce: {
            wpautop: true,
            toolbar1: 'bold,italic,bullist,numlist,link,unlink,undo,redo',
            setup: function( editor ) {
              editor.on( 'init', function() {
                if ( editor.getContent() !== ( props.value || '' ) ) {
                  editor.setContent( props.value || '' );
                }
              } );

              editor.on( 'change keyup input undo redo', function() {
                var value = editor.getContent();

                if ( value === lastValueRef.current ) {
                  return;
                }

                lastValueRef.current = value;
                props.onChange( value );
              } );
            }
          }
        }
      );

      textarea = document.getElementById( editorId );

      if ( textarea && ! textareaEventsBoundRef.current ) {
        textarea.addEventListener( 'input', syncTextareaValue );
        textarea.addEventListener( 'change', syncTextareaValue );
        textareaEventsBoundRef.current = true;
      }

      return function() {
        var currentTextarea = document.getElementById( editorId );

        if ( currentTextarea && textareaEventsBoundRef.current ) {
          currentTextarea.removeEventListener( 'input', syncTextareaValue );
          currentTextarea.removeEventListener( 'change', syncTextareaValue );
        }

        textareaEventsBoundRef.current = false;

        if ( window.wp && window.wp.editor && 'function' === typeof window.wp.editor.remove ) {
          window.wp.editor.remove( editorId );
        }
      };
    }, [] );

    useEffect( function() {
      var nextValue = props.value || '';

      if ( nextValue === lastValueRef.current ) {
        return;
      }

      lastValueRef.current = nextValue;

      if ( window.tinymce && 'function' === typeof window.tinymce.get ) {
        var editor = window.tinymce.get( editorId );

        if ( editor && editor.initialized && editor.getContent() !== nextValue ) {
          editor.setContent( nextValue );
        }
      }

      var textarea = document.getElementById( editorId );

      if ( textarea && textarea.value !== nextValue ) {
        textarea.value = nextValue;
      }
    }, [ props.value ] );

    return createElement(
      'div',
      {
        className: 'pdt-content-visibility-panel__tinymce'
      },
      createElement(
        'label',
        {
          className: 'components-base-control__label',
          htmlFor: editorId
        },
        props.label
      ),
      createElement(
        'p',
        {
          className: 'description'
        },
        props.help
      ),
      createElement( 'textarea', {
        id: editorId,
        defaultValue: props.value || '',
        rows: 6
      } )
    );
  }

  function ContentVisibilityPanel() {
    var meta = useSelect( function( select ) {
      return select( 'core/editor' ).getEditedPostAttribute( 'meta' ) || {};
    } );

    var dispatch = useDispatch( 'core/editor' );

    var mode = meta[ keys.mode ] || 'public';
    var selectedRoles = Array.isArray( meta[ keys.roles ] ) ? meta[ keys.roles ] : [];
    var deniedBehavior = meta[ keys.denied ] || 'inherit';
    var compatibility = meta[ keys.compatibility ] || 'inherit';
    var redirectUrl = meta[ keys.redirectUrl ] || '';
    var customMessage = meta[ keys.message ] || '';

    function updateMeta( key, value ) {
      var payload = {};
      payload[ key ] = value;
      dispatch.editPost( { meta: payload } );
    }

    function toggleRole( role, isChecked ) {
      var nextRoles = selectedRoles.slice();
      var index = nextRoles.indexOf( role );

      if ( isChecked && index === -1 ) {
        nextRoles.push( role );
      }

      if ( ! isChecked && index !== -1 ) {
        nextRoles.splice( index, 1 );
      }

      updateMeta( keys.roles, nextRoles );
    }

    var children = [
      createElement(
        Notice,
        {
          key: 'description',
          status: 'info',
          isDismissible: false
        },
        config.labels.panelDescription
      ),
      createElement( SelectControl, {
        key: 'mode',
        label: config.labels.visibility,
        value: mode,
        options: toOptions( config.visibilityModes ),
        onChange: function( value ) {
          updateMeta( keys.mode, value );
        }
      } ),
      createElement(
        'p',
        {
          key: 'mode-help',
          className: 'description'
        },
        mode === 'show_roles' ? config.labels.legacyShowRolesHelp : config.labels.accessRuleHelp
      ),
      createElement(
        'p',
        { key: 'defaults-link', className: 'pdt-content-visibility-panel__defaults description' },
        createElement(
          'a',
          {
            href: config.defaultSettingsUrl || '#',
            target: '_blank',
            rel: 'noopener noreferrer'
          },
          config.labels.defaultSettings
        ),
        ' ',
        config.labels.defaultSettingsHelp
      )
    ];

    if ( mode === 'show_roles' || mode === 'hide_roles' ) {
      children.push(
        createElement(
          'div',
          { key: 'roles-wrap', className: 'pdt-content-visibility-panel__roles' },
          createElement( 'strong', null, config.labels.roles ),
          createElement(
            'p',
            { className: 'description' },
            mode === 'show_roles' ? config.labels.legacyShowRolesHelp : config.labels.rolesHelp
          ),
          config.roles.map( function( role ) {
            return createElement( CheckboxControl, {
              key: role.value,
              label: role.label,
              checked: selectedRoles.indexOf( role.value ) !== -1,
              onChange: function( isChecked ) {
                toggleRole( role.value, isChecked );
              }
            } );
          } )
        )
      );
    }

    children.push(
      createElement( SelectControl, {
        key: 'behavior',
        label: config.labels.deniedBehavior,
        value: deniedBehavior,
        options: toOptions( config.deniedBehaviors ),
        onChange: function( value ) {
          updateMeta( keys.denied, value );
        }
      } )
    );

    if ( deniedBehavior === 'custom_redirect' ) {
      children.push(
        createElement( TextControl, {
          key: 'redirect',
          type: 'url',
          label: config.labels.customRedirectUrl,
          value: redirectUrl,
          placeholder: config.redirectPlaceholder || '',
          onChange: function( value ) {
            updateMeta( keys.redirectUrl, value );
          }
        } )
      );
    }

    if ( deniedBehavior === 'message' ) {
      children.push(
        createElement( TinyMCEControl, {
          key: 'message',
          label: config.labels.customMessage,
          value: customMessage,
          help: config.labels.customMessageHelp,
          onChange: function( value ) {
            updateMeta( keys.message, value );
          }
        } )
      );
    }

    children.push(
      createElement( SelectControl, {
        key: 'compatibility',
        label: config.labels.compatibility,
        value: compatibility,
        options: toOptions( config.compatibilityModes ),
        onChange: function( value ) {
          updateMeta( keys.compatibility, value );
        },
        help: config.labels.compatibilityHelp
      } )
    );

    return createElement(
      PluginDocumentSettingPanel,
      {
        name: 'pdt-content-visibility',
        title: config.labels.panelTitle,
        className: 'pdt-content-visibility-panel'
      },
      createElement( Fragment, null, children )
    );
  }

  registerPlugin( 'pdt-content-visibility', {
    render: ContentVisibilityPanel,
    icon: 'visibility'
  } );
}( window.wp ) );
