import $ from 'jquery';
import Vue from 'vue';
import VueApollo from 'vue-apollo';
import createFlash from '~/flash';
import {
  isInIssuePage,
  isInDesignPage,
  isInIncidentPage,
  parseBoolean,
} from '~/lib/utils/common_utils';
import { __ } from '~/locale';
import SidebarConfidentialityWidget from '~/sidebar/components/confidential/sidebar_confidentiality_widget.vue';
import { apolloProvider } from '~/sidebar/graphql';
import Translate from '../vue_shared/translate';
import SidebarAssignees from './components/assignees/sidebar_assignees.vue';
import CopyEmailToClipboard from './components/copy_email_to_clipboard.vue';
import SidebarLabels from './components/labels/sidebar_labels.vue';
import IssuableLockForm from './components/lock/issuable_lock_form.vue';
import sidebarParticipants from './components/participants/sidebar_participants.vue';
import SidebarReviewers from './components/reviewers/sidebar_reviewers.vue';
import SidebarSeverity from './components/severity/sidebar_severity.vue';
import sidebarSubscriptions from './components/subscriptions/sidebar_subscriptions.vue';
import SidebarTimeTracking from './components/time_tracking/sidebar_time_tracking.vue';
import SidebarMoveIssue from './lib/sidebar_move_issue';

Vue.use(Translate);
Vue.use(VueApollo);

function getSidebarOptions(sidebarOptEl = document.querySelector('.js-sidebar-options')) {
  return JSON.parse(sidebarOptEl.innerHTML);
}

/**
 * Extracts the list of assignees with availability information from a hidden input
 * field and converts to a key:value pair for use in the sidebar assignees component.
 * The assignee username is used as the key and their busy status is the value
 *
 * e.g { root: 'busy', admin: '' }
 *
 * @returns {Object}
 */
function getSidebarAssigneeAvailabilityData() {
  const sidebarAssigneeEl = document.querySelectorAll('.js-sidebar-assignee-data input');
  return Array.from(sidebarAssigneeEl)
    .map((el) => el.dataset)
    .reduce(
      (acc, { username, availability = '' }) => ({
        ...acc,
        [username]: availability,
      }),
      {},
    );
}

function mountAssigneesComponent(mediator) {
  const el = document.getElementById('js-vue-sidebar-assignees');

  if (!el) return;

  const { iid, fullPath } = getSidebarOptions();
  const assigneeAvailabilityStatus = getSidebarAssigneeAvailabilityData();
  // eslint-disable-next-line no-new
  new Vue({
    el,
    apolloProvider,
    components: {
      SidebarAssignees,
    },
    render: (createElement) =>
      createElement('sidebar-assignees', {
        props: {
          mediator,
          issuableIid: String(iid),
          projectPath: fullPath,
          field: el.dataset.field,
          signedIn: el.hasAttribute('data-signed-in'),
          issuableType:
            isInIssuePage() || isInIncidentPage() || isInDesignPage() ? 'issue' : 'merge_request',
          assigneeAvailabilityStatus,
        },
      }),
  });
}

function mountReviewersComponent(mediator) {
  const el = document.getElementById('js-vue-sidebar-reviewers');

  if (!el) return;

  const { iid, fullPath } = getSidebarOptions();
  // eslint-disable-next-line no-new
  new Vue({
    el,
    apolloProvider,
    components: {
      SidebarReviewers,
    },
    render: (createElement) =>
      createElement('sidebar-reviewers', {
        props: {
          mediator,
          issuableIid: String(iid),
          projectPath: fullPath,
          field: el.dataset.field,
          issuableType: isInIssuePage() || isInDesignPage() ? 'issue' : 'merge_request',
        },
      }),
  });
}

export function mountSidebarLabels() {
  const el = document.querySelector('.js-sidebar-labels');

  if (!el) {
    return false;
  }

  return new Vue({
    el,
    apolloProvider,
    provide: {
      ...el.dataset,
      allowLabelCreate: parseBoolean(el.dataset.allowLabelCreate),
      allowLabelEdit: parseBoolean(el.dataset.canEdit),
      allowScopedLabels: parseBoolean(el.dataset.allowScopedLabels),
      initiallySelectedLabels: JSON.parse(el.dataset.selectedLabels),
    },
    render: (createElement) => createElement(SidebarLabels),
  });
}

function mountConfidentialComponent() {
  const el = document.getElementById('js-confidential-entry-point');
  if (!el) {
    return;
  }

  const { fullPath, iid } = getSidebarOptions();
  const dataNode = document.getElementById('js-confidential-issue-data');
  const initialData = JSON.parse(dataNode.innerHTML);

  // eslint-disable-next-line no-new
  new Vue({
    el,
    apolloProvider,
    components: {
      SidebarConfidentialityWidget,
    },
    provide: {
      iid: String(iid),
      fullPath,
      canUpdate: initialData.is_editable,
    },

    render: (createElement) =>
      createElement('sidebar-confidentiality-widget', {
        props: {
          issuableType:
            isInIssuePage() || isInIncidentPage() || isInDesignPage() ? 'issue' : 'merge_request',
        },
      }),
  });
}

function mountLockComponent() {
  const el = document.getElementById('js-lock-entry-point');

  if (!el) {
    return;
  }

  const { fullPath } = getSidebarOptions();

  const dataNode = document.getElementById('js-lock-issue-data');
  const initialData = JSON.parse(dataNode.innerHTML);

  let importStore;
  if (isInIssuePage() || isInIncidentPage()) {
    importStore = import(/* webpackChunkName: 'notesStore' */ '~/notes/stores').then(
      ({ store }) => store,
    );
  } else {
    importStore = import(/* webpackChunkName: 'mrNotesStore' */ '~/mr_notes/stores').then(
      (store) => store.default,
    );
  }

  importStore
    .then(
      (store) =>
        new Vue({
          el,
          store,
          provide: {
            fullPath,
          },
          render: (createElement) =>
            createElement(IssuableLockForm, {
              props: {
                isEditable: initialData.is_editable,
              },
            }),
        }),
    )
    .catch(() => {
      createFlash({ message: __('Failed to load sidebar lock status') });
    });
}

function mountParticipantsComponent(mediator) {
  const el = document.querySelector('.js-sidebar-participants-entry-point');

  if (!el) return;

  // eslint-disable-next-line no-new
  new Vue({
    el,
    components: {
      sidebarParticipants,
    },
    render: (createElement) =>
      createElement('sidebar-participants', {
        props: {
          mediator,
        },
      }),
  });
}

function mountSubscriptionsComponent(mediator) {
  const el = document.querySelector('.js-sidebar-subscriptions-entry-point');

  if (!el) return;

  // eslint-disable-next-line no-new
  new Vue({
    el,
    components: {
      sidebarSubscriptions,
    },
    render: (createElement) =>
      createElement('sidebar-subscriptions', {
        props: {
          mediator,
        },
      }),
  });
}

function mountTimeTrackingComponent() {
  const el = document.getElementById('issuable-time-tracker');

  if (!el) return;

  // eslint-disable-next-line no-new
  new Vue({
    el,
    components: {
      SidebarTimeTracking,
    },
    render: (createElement) => createElement('sidebar-time-tracking', {}),
  });
}

function mountSeverityComponent() {
  const severityContainerEl = document.querySelector('#js-severity');

  if (!severityContainerEl) {
    return false;
  }

  const { fullPath, iid, severity } = getSidebarOptions();

  return new Vue({
    el: severityContainerEl,
    apolloProvider,
    components: {
      SidebarSeverity,
    },
    render: (createElement) =>
      createElement('sidebar-severity', {
        props: {
          projectPath: fullPath,
          iid: String(iid),
          initialSeverity: severity.toUpperCase(),
        },
      }),
  });
}

function mountCopyEmailComponent() {
  const el = document.getElementById('issuable-copy-email');

  if (!el) return;

  const { createNoteEmail } = getSidebarOptions();

  // eslint-disable-next-line no-new
  new Vue({
    el,
    render: (createElement) =>
      createElement(CopyEmailToClipboard, { props: { copyText: createNoteEmail } }),
  });
}

export function mountSidebar(mediator) {
  mountAssigneesComponent(mediator);
  mountReviewersComponent(mediator);
  mountConfidentialComponent(mediator);
  mountLockComponent();
  mountParticipantsComponent(mediator);
  mountSubscriptionsComponent(mediator);
  mountCopyEmailComponent();

  new SidebarMoveIssue(
    mediator,
    $('.js-move-issue'),
    $('.js-move-issue-confirmation-button'),
  ).init();

  mountTimeTrackingComponent();

  mountSeverityComponent();
}

export { getSidebarOptions };
