/* global buffer */
/* eslint-disable react/jsx-filename-extension */

// TODO: Make composer/index.js the only file we import stuff from, it should be the
// only point of contact b/w the composer package and its interfaces

import React from 'react';
import ReactDOM from 'react-dom';
import { events } from '../composer';
import AppStore from '../composer/stores/AppStore';
import AppInitActionCreators from '../composer/action-creators/AppInitActionCreators';
import AppActionCreators from '../composer/action-creators/AppActionCreators';
import { formatInputData, formatUserData, extractPropsFromBufferGlobal }
  from '../composer/utils/DataImportUtils';
import { DataImportEnvironments, bufferOrigins, bufferOriginRegex, AppEnvironments }
  from '../composer/AppConstants';
import App from '../composer/components/App';

let containerNode;
let prevImportedData;

const eventHooks = {
  loadedComposer: () => {
    const { appEnvironment, shouldDisplayHelpButton } = AppStore.getMetaData();
    const { isFreeUser } = AppStore.getUserData();

    if (appEnvironment === AppEnvironments.EXTENSION) {
      // Let the extension know the composer window is loaded
      if (window.location !== window.parent.location) {
        const message = {
          type: 'buffer_loaded',
          data: {
            userData: {
              shouldDisplayAwesomeCTA: isFreeUser,
              shouldDisplayHelpButton,
            },
          },
        };

        window.parent.postMessage(JSON.stringify(message), '*');
      }
    }
  },

  backdropClicked: () => {
    const { appEnvironment, environment } = AppStore.getMetaData();
    const { preserveStateOnClose } = AppStore.getOptions();

    if (appEnvironment === AppEnvironments.WEB_DASHBOARD) {
      window.parent.postMessage({
        type: 'backdrop-click',
        preserveStateOnClose,
      }, bufferOrigins.get(environment));

      AppActionCreators.markAppAsNotLoaded();
    }
  },

  savedDrafts: ({ message }) => {
    const { appEnvironment, environment } = AppStore.getMetaData();
    const { preserveStateOnClose } = AppStore.getOptions();

    if (appEnvironment === AppEnvironments.WEB_DASHBOARD) {
      window.parent.postMessage({
        type: 'drafts-saved',
        preserveStateOnClose,
        message,
      }, bufferOrigins.get(environment));

      if (!preserveStateOnClose) AppActionCreators.markAppAsNotLoaded();
      else softReset();
    }

    if (appEnvironment === AppEnvironments.EXTENSION) {
      setTimeout(() => {
        eventHooks.closedComposer();
        AppActionCreators.markAppAsNotLoaded();
      }, 3000);
    }
  },

  closedComposer: () => {
    const { appEnvironment } = AppStore.getMetaData();

    if (appEnvironment === AppEnvironments.EXTENSION) {
      // Send message to the extension to close it
      const message = {
        type: 'buffermessage',
        data: { sent: true },
      };

      window.parent.postMessage(JSON.stringify(message), '*');

      /**
       * The Buffer extension's share dialog is sometimes open in a separate tab.
       * Legacy versions of the Buffer extension were relying on the tab to close itself.
       * Even though new versions of the extension handle the closing of tabs themselves,
       * we still need a window.close() fallback while older versions are still out there.
       */
      if (window.location === window.parent.location) {
        window.close();
      }
    }
  },

  hasResetAndHiddenComposer: () => {
    const { appEnvironment, environment } = AppStore.getMetaData();

    if (appEnvironment === AppEnvironments.WEB_DASHBOARD) {
      window.parent.postMessage({
        type: 'composer-was-reset-and-hidden',
      }, bufferOrigins.get(environment));
    }
  },

  showUpgradeModal: () => {
    const { appEnvironment, environment } = AppStore.getMetaData();

    if (appEnvironment === AppEnvironments.WEB_DASHBOARD) {
      window.parent.postMessage({
        type: 'click-upgrade-modal',
      }, bufferOrigins.get(environment));
    }
  }
};

events.on('loaded', eventHooks.loadedComposer);
events.on('backdrop-clicked', eventHooks.backdropClicked);
events.on('saved-drafts', eventHooks.savedDrafts);
events.on('closed', eventHooks.closedComposer);
events.on('show-upgrade-modal', eventHooks.showUpgradeModal);

/**
 * Data imported from other environments (e.g. WEB_DASHBOARD) can be incomplete:
 * for those missing bits, make sure we fill in the blanks with default data, imported
 * from the BOOKMARKLET_PHP env.
 */
const completeHydration = ({
  profilesData, userData, metaData, csrfToken, imageDimensionsKey, options,
}) => {
  const bookmarkletBufferGlobal = buffer;
  const defaultUserData = formatUserData(DataImportEnvironments.BOOKMARKLET_PHP, {
    userData: bookmarkletBufferGlobal.user,
  });

  return {
    userData: Object.assign({}, defaultUserData, userData),
    metaData,
    profilesData,
    csrfToken,
    imageDimensionsKey,
    options,
  };
};

// options.preserveStateOnClose is used to reset the composer's state on close.
// However, if options.preserveStateOnClose is true in a previous composer instance,
// since this is a singleton, we'll need to reset the composer's state on load
// if the new instance has `options.preserveStateOnClose === false`.
// When state was preserved on close and a new composer instance is being initiated,
// we'll also auto-focus the composer to get back into an easy-to-type-in state.
const runNecessaryPreInitOperations = (() => {
  let prevPreserveStateOnClose = false;

  return ({ preserveStateOnClose, resetSelectedProfiles }, profilesData) => {
    if (preserveStateOnClose === false && preserveStateOnClose !== prevPreserveStateOnClose) {
      reset();
    } else if (preserveStateOnClose === true && preserveStateOnClose === prevPreserveStateOnClose) {
      AppActionCreators.forceEditorFocus();

      if (resetSelectedProfiles) AppActionCreators.resetSelectedProfiles(profilesData);
      else AppActionCreators.markAppAsLoaded();
    }
    prevPreserveStateOnClose = preserveStateOnClose;
  };
})();

const init = (importedData = {}) => {
  if (!containerNode) {
    throw new Error('setup() should be run before init(), and passed a valid container node');
  }

  prevImportedData = importedData;

  const { profilesData, userData, metaData, csrfToken, imageDimensionsKey, options } =
    completeHydration(importedData);

  runNecessaryPreInitOperations(options, profilesData);

  ReactDOM.render(
    <App
      profilesData={profilesData}
      userData={userData}
      metaData={metaData}
      csrfToken={csrfToken}
      imageDimensionsKey={imageDimensionsKey}
      options={options}
    />,
    containerNode
  );
};

const reset = () => {
  if (!containerNode) {
    throw new Error('reset() should be run before init(), and passed a valid container node');
  }

  AppInitActionCreators.resetData();
  ReactDOM.unmountComponentAtNode(containerNode);
};

const softReset = () => {
  AppInitActionCreators.softResetData();
};

const onWindowMessage = (e) => {
  const isBufferOrigin = bufferOriginRegex.test(e.origin);
  if (!isBufferOrigin) return;

  if (e.data.type === 'init') {
    const { env, data, options } = e.data;
    const formattedData = formatInputData({ env, data, options });
    init(formattedData);
  }

  if (e.data.type === 'reset-and-hide') {
    eventHooks.hasResetAndHiddenComposer(); // Order matters, this needs metadata to exist
    reset();
  }
};

const setup = (node) => {
  containerNode = node;

  const bufferGlobal = buffer;
  const shouldInitOnLoad = bufferGlobal.meta.application === 'OVERLAY'; // Extension

  if (shouldInitOnLoad) {
    const { userData, metaData, csrfToken, imageDimensionsKey } =
      extractPropsFromBufferGlobal(bufferGlobal);

    const formattedData = formatInputData({
      env: 'BOOKMARKLET_PHP',
      data: {
        profiles: bufferGlobal.user.profiles,
        userData,
        metaData,
        csrfToken,
        imageDimensionsKey,
      },
    });

    init(formattedData);
  }

  window.addEventListener('message', onWindowMessage);
};

window.tpSetup = setup;
