import Vue from 'vue';
import Visibility from 'visibilityjs';
import PipelinesService from './services/pipelines_service';
import eventHub from './event_hub';
import PipelinesTableComponent from '../vue_shared/components/pipelines_table';
import TablePaginationComponent from '../vue_shared/components/table_pagination';
import EmptyState from './components/empty_state.vue';
import ErrorState from './components/error_state.vue';
import NavigationTabs from './components/navigation_tabs';
import NavigationControls from './components/nav_controls';
import Poll from '../lib/utils/poll';

export default {
  props: {
    store: {
      type: Object,
      required: true,
    },
  },

  components: {
    'gl-pagination': TablePaginationComponent,
    'pipelines-table-component': PipelinesTableComponent,
    'empty-state': EmptyState,
    'error-state': ErrorState,
    'navigation-tabs': NavigationTabs,
    'navigation-controls': NavigationControls,
  },

  data() {
    const pipelinesData = document.querySelector('#pipelines-list-vue').dataset;

    return {
      endpoint: pipelinesData.endpoint,
      cssClass: pipelinesData.cssClass,
      helpPagePath: pipelinesData.helpPagePath,
      newPipelinePath: pipelinesData.newPipelinePath,
      canCreatePipeline: pipelinesData.canCreatePipeline,
      allPath: pipelinesData.allPath,
      pendingPath: pipelinesData.pendingPath,
      runningPath: pipelinesData.runningPath,
      finishedPath: pipelinesData.finishedPath,
      branchesPath: pipelinesData.branchesPath,
      tagsPath: pipelinesData.tagsPath,
      hasCi: pipelinesData.hasCi,
      ciLintPath: pipelinesData.ciLintPath,
      state: this.store.state,
      apiScope: 'all',
      pagenum: 1,
      isLoading: false,
      hasError: false,
      isMakingRequest: false,
    };
  },

  computed: {
    canCreatePipelineParsed() {
      return gl.utils.convertPermissionToBoolean(this.canCreatePipeline);
    },

    scope() {
      const scope = gl.utils.getParameterByName('scope');
      return scope === null ? 'all' : scope;
    },

    shouldRenderErrorState() {
      return this.hasError && !this.isLoading;
    },

    /**
    * The empty state should only be rendered when the request is made to fetch all pipelines
    * and none is returned.
    *
    * @return {Boolean}
    */
    shouldRenderEmptyState() {
      return !this.isLoading &&
        !this.hasError &&
        !this.state.pipelines.length &&
        (this.scope === 'all' || this.scope === null);
    },

    /**
     * When a specific scope does not have pipelines we render a message.
     *
     * @return {Boolean}
     */
    shouldRenderNoPipelinesMessage() {
      return !this.isLoading &&
        !this.hasError &&
        !this.state.pipelines.length &&
        this.scope !== 'all' &&
        this.scope !== null;
    },

    shouldRenderTable() {
      return !this.hasError &&
        !this.isLoading && this.state.pipelines.length;
    },

    /**
    * Pagination should only be rendered when there is more than one page.
    *
    * @return {Boolean}
    */
    shouldRenderPagination() {
      return !this.isLoading &&
        this.state.pipelines.length &&
        this.state.pageInfo.total > this.state.pageInfo.perPage;
    },

    hasCiEnabled() {
      return this.hasCi !== undefined;
    },

    paths() {
      return {
        allPath: this.allPath,
        pendingPath: this.pendingPath,
        finishedPath: this.finishedPath,
        runningPath: this.runningPath,
        branchesPath: this.branchesPath,
        tagsPath: this.tagsPath,
      };
    },

    pageParameter() {
      return gl.utils.getParameterByName('page') || this.pagenum;
    },

    scopeParameter() {
      return gl.utils.getParameterByName('scope') || this.apiScope;
    },
  },

  created() {
    this.service = new PipelinesService(this.endpoint);

    const poll = new Poll({
      resource: this.service,
      method: 'getPipelines',
      data: { page: this.pageParameter, scope: this.scopeParameter },
      successCallback: this.successCallback,
      errorCallback: this.errorCallback,
      notificationCallback: this.setIsMakingRequest,
    });

    if (!Visibility.hidden()) {
      this.isLoading = true;
      poll.makeRequest();
    }

    Visibility.change(() => {
      if (!Visibility.hidden()) {
        poll.restart();
      } else {
        poll.stop();
      }
    });

    eventHub.$on('refreshPipelines', this.fetchPipelines);
  },

  beforeUpdate() {
    if (this.state.pipelines.length &&
        this.$children &&
        !this.isMakingRequest &&
        !this.isLoading) {
      this.store.startTimeAgoLoops.call(this, Vue);
    }
  },

  beforeDestroyed() {
    eventHub.$off('refreshPipelines');
  },

  methods: {
    /**
     * Will change the page number and update the URL.
     *
     * @param  {Number} pageNumber desired page to go to.
     */
    change(pageNumber) {
      const param = gl.utils.setParamInURL('page', pageNumber);

      gl.utils.visitUrl(param);
      return param;
    },

    fetchPipelines() {
      if (!this.isMakingRequest) {
        this.isLoading = true;

        this.service.getPipelines({ scope: this.scopeParameter, page: this.pageParameter })
          .then(response => this.successCallback(response))
          .catch(() => this.errorCallback());
      }
    },

    successCallback(resp) {
      const response = {
        headers: resp.headers,
        body: resp.json(),
      };

      this.store.storeCount(response.body.count);
      this.store.storePipelines(response.body.pipelines);
      this.store.storePagination(response.headers);

      this.isLoading = false;
    },

    errorCallback() {
      this.hasError = true;
      this.isLoading = false;
    },

    setIsMakingRequest(isMakingRequest) {
      this.isMakingRequest = isMakingRequest;
    },
  },

  template: `
    <div :class="cssClass">

      <div
        class="top-area scrolling-tabs-container inner-page-scroll-tabs"
        v-if="!isLoading && !shouldRenderEmptyState">
        <div class="fade-left">
          <i class="fa fa-angle-left" aria-hidden="true"></i>
        </div>
        <div class="fade-right">
          <i class="fa fa-angle-right" aria-hidden="true"></i>
        </div>
        <navigation-tabs
          :scope="scope"
          :count="state.count"
          :paths="paths" />

        <navigation-controls
          :new-pipeline-path="newPipelinePath"
          :has-ci-enabled="hasCiEnabled"
          :help-page-path="helpPagePath"
          :ciLintPath="ciLintPath"
          :can-create-pipeline="canCreatePipelineParsed " />
      </div>

      <div class="content-list pipelines">

        <div
          class="realtime-loading"
          v-if="isLoading">
          <i
            class="fa fa-spinner fa-spin"
            aria-hidden="true" />
        </div>

        <empty-state
          v-if="shouldRenderEmptyState"
          :help-page-path="helpPagePath" />

        <error-state v-if="shouldRenderErrorState" />

        <div
          class="blank-state blank-state-no-icon"
          v-if="shouldRenderNoPipelinesMessage">
          <h2 class="blank-state-title js-blank-state-title">No pipelines to show.</h2>
        </div>

        <div
          class="table-holder"
          v-if="shouldRenderTable">

          <pipelines-table-component
            :pipelines="state.pipelines"
            :service="service"/>
        </div>

        <gl-pagination
          v-if="shouldRenderPagination"
          :pagenum="pagenum"
          :change="change"
          :count="state.count.all"
          :pageInfo="state.pageInfo"/>
      </div>
    </div>
  `,
};
