import History from './utils/History';
import Pane from './utils/Pane';
import Search from './components/Search';
import ReplyComposer from './components/ReplyComposer';
import DiscussionPage from './components/DiscussionPage';
import SignUpModal from './components/SignUpModal';
import HeaderPrimary from './components/HeaderPrimary';
import HeaderSecondary from './components/HeaderSecondary';
import Composer from './components/Composer';
import DiscussionRenamedNotification from './components/DiscussionRenamedNotification';
import CommentPost from './components/CommentPost';
import DiscussionRenamedPost from './components/DiscussionRenamedPost';
import routes from './routes';
import alertEmailConfirmation from './utils/alertEmailConfirmation';
import Application from '../common/Application';
import Navigation from '../common/components/Navigation';

export default class ForumApplication extends Application {
  /**
   * A map of notification types to their components.
   *
   * @type {Object}
   */
  notificationComponents = {
    discussionRenamed: DiscussionRenamedNotification
  };
  /**
   * A map of post types to their components.
   *
   * @type {Object}
   */
  postComponents = {
    comment: CommentPost,
    discussionRenamed: DiscussionRenamedPost
  };

  /**
   * The page's search component instance.
   *
   * @type {Search}
   */
  search = new Search();

  /**
   * An object which controls the state of the page's side pane.
   *
   * @type {Pane}
   */
  pane = null;

  /**
   * An object which controls the state of the page's drawer.
   *
   * @type {Drawer}
   */
  drawer = null;

  /**
   * The app's history stack, which keeps track of which routes the user visits
   * so that they can easily navigate back to the previous route.
   *
   * @type {History}
   */
  history = new History();

  constructor() {
    super();

    routes(this);
  }

  /**
   * @inheritdoc
   */
  mount() {
    // Get the configured default route and update that route's path to be '/'.
    // Push the homepage as the first route, so that the user will always be
    // able to click on the 'back' button to go home, regardless of which page
    // they started on.
    const defaultRoute = this.forum.attribute('defaultRoute');
    let defaultAction = 'index';

    for (const i in this.routes) {
      if (this.routes[i].path === defaultRoute) defaultAction = i;
    }

    this.routes[defaultAction].path = '/';
    this.history.push(defaultAction, this.translator.trans('core.forum.header.back_to_index_tooltip'), '/');

    m.mount(document.getElementById('app-navigation'), Navigation.component({className: 'App-backControl', drawer: true}));
    m.mount(document.getElementById('header-navigation'), Navigation.component());
    m.mount(document.getElementById('header-primary'), HeaderPrimary.component());
    m.mount(document.getElementById('header-secondary'), HeaderSecondary.component());

    this.pane = new Pane(document.getElementById('app'));
    this.composer = m.mount(document.getElementById('composer'), Composer.component());

    m.route.mode = 'pathname';
    super.mount(this.forum.attribute('basePath'));

    alertEmailConfirmation(this);

    // Route the home link back home when clicked. We do not want it to register
    // if the user is opening it in a new tab, however.
    $('#home-link').click(e => {
      if (e.ctrlKey || e.metaKey || e.which === 2) return;
      e.preventDefault();
      app.history.home();

      // Reload the current user so that their unread notification count is refreshed.
      if (app.session.user) {
        app.store.find('users', app.session.user.id());
        m.redraw();
      }
    });
  }

  /**
   * Check whether or not the user is currently composing a reply to a
   * discussion.
   *
   * @param {Discussion} discussion
   * @return {Boolean}
   */
  composingReplyTo(discussion) {
    return this.composer.component instanceof ReplyComposer &&
      this.composer.component.props.discussion === discussion &&
      this.composer.position !== Composer.PositionEnum.HIDDEN;
  }

  /**
   * Check whether or not the user is currently viewing a discussion.
   *
   * @param {Discussion} discussion
   * @return {Boolean}
   */
  viewingDiscussion(discussion) {
    return this.current instanceof DiscussionPage &&
      this.current.discussion === discussion;
  }

  /**
   * Callback for when an external authenticator (social login) action has
   * completed.
   *
   * If the payload indicates that the user has been logged in, then the page
   * will be reloaded. Otherwise, a SignUpModal will be opened, prefilled
   * with the provided details.
   *
   * @param {Object} payload A dictionary of props to pass into the sign up
   *     modal. A truthy `loggedIn` prop indicates that the user has logged
   *     in, and thus the page is reloaded.
   * @public
   */
  authenticationComplete(payload) {
    if (payload.loggedIn) {
      window.location.reload();
    } else {
      const modal = new SignUpModal(payload);
      this.modal.show(modal);
    }
  }
}
