<script>
  import _ from 'underscore';
  import { __, sprintf, s__ } from '../../locale';
  import createFlash from '../../flash';
  import PipelinesService from '../services/pipelines_service';
  import pipelinesMixin from '../mixins/pipelines';
  import TablePagination from '../../vue_shared/components/table_pagination.vue';
  import NavigationTabs from '../../vue_shared/components/navigation_tabs.vue';
  import NavigationControls from './nav_controls.vue';
  import {
    getParameterByName,
    parseQueryStringIntoObject,
  } from '../../lib/utils/common_utils';
  import CIPaginationMixin from '../../vue_shared/mixins/ci_pagination_api_mixin';

  export default {
    components: {
      TablePagination,
      NavigationTabs,
      NavigationControls,
    },
    mixins: [
      pipelinesMixin,
      CIPaginationMixin,
    ],
    props: {
      store: {
        type: Object,
        required: true,
      },
      // Can be rendered in 3 different places, with some visual differences
      // Accepts root | child
      // `root` -> main view
      // `child` -> rendered inside MR or Commit View
      viewType: {
        type: String,
        required: false,
        default: 'root',
      },
      endpoint: {
        type: String,
        required: true,
      },
      helpPagePath: {
        type: String,
        required: true,
      },
      emptyStateSvgPath: {
        type: String,
        required: true,
      },
      errorStateSvgPath: {
        type: String,
        required: true,
      },
      noPipelinesSvgPath: {
        type: String,
        required: true,
      },
      autoDevopsPath: {
        type: String,
        required: true,
      },
      hasGitlabCi: {
        type: Boolean,
        required: true,
      },
      canCreatePipeline: {
        type: Boolean,
        required: true,
      },
      ciLintPath: {
        type: String,
        required: false,
        default: null,
      },
      resetCachePath: {
        type: String,
        required: false,
        default: null,
      },
      newPipelinePath: {
        type: String,
        required: false,
        default: null,
      },
    },
    data() {
      return {
        // Start with loading state to avoid a glitch when the empty state will be rendered
        isLoading: true,
        state: this.store.state,
        scope: getParameterByName('scope') || 'all',
        page: getParameterByName('page') || '1',
        requestData: {},
        isResetCacheButtonLoading: false,
      };
    },
    stateMap: {
      // with tabs
      loading: 'loading',
      tableList: 'tableList',
      error: 'error',
      emptyTab: 'emptyTab',

      // without tabs
      emptyState: 'emptyState',
    },
    scopes: {
      all: 'all',
      pending: 'pending',
      running: 'running',
      finished: 'finished',
      branches: 'branches',
      tags: 'tags',
    },
    computed: {
      /**
       * `hasGitlabCi` handles both internal and external CI.
       * The order on which  the checks are made in this method is
       * important to guarantee we handle all the corner cases.
       */
      stateToRender() {
        const { stateMap } = this.$options;

        if (this.isLoading) {
          return stateMap.loading;
        }

        if (this.hasError) {
          return stateMap.error;
        }

        if (this.state.pipelines.length) {
          return stateMap.tableList;
        }

        if ((this.scope !== 'all' && this.scope !== null) || this.hasGitlabCi) {
          return stateMap.emptyTab;
        }

        return stateMap.emptyState;
      },
      /**
       * Tabs are rendered in all states except empty state.
       * They are not rendered before the first request to avoid a flicker on first load.
       */
      shouldRenderTabs() {
        const { stateMap } = this.$options;
        return this.hasMadeRequest &&
          [
            stateMap.loading,
            stateMap.tableList,
            stateMap.error,
            stateMap.emptyTab,
          ].includes(this.stateToRender);
      },

      shouldRenderButtons() {
        return (this.newPipelinePath ||
          this.resetCachePath ||
          this.ciLintPath) && this.shouldRenderTabs;
      },

      shouldRenderPagination() {
        return !this.isLoading &&
          this.state.pipelines.length &&
          this.state.pageInfo.total > this.state.pageInfo.perPage;
      },

      emptyTabMessage() {
        const { scopes } = this.$options;
        const possibleScopes = [scopes.pending, scopes.running, scopes.finished];

        if (possibleScopes.includes(this.scope)) {
          return sprintf(s__('Pipelines|There are currently no %{scope} pipelines.'), {
            scope: this.scope,
          });
        }

        return s__('Pipelines|There are currently no pipelines.');
      },

      tabs() {
        const { count } = this.state;
        const { scopes } = this.$options;

        return [
          {
            name: __('All'),
            scope: scopes.all,
            count: count.all,
            isActive: this.scope === 'all',
          },
          {
            name: __('Pending'),
            scope: scopes.pending,
            count: count.pending,
            isActive: this.scope === 'pending',
          },
          {
            name: __('Running'),
            scope: scopes.running,
            count: count.running,
            isActive: this.scope === 'running',
          },
          {
            name: __('Finished'),
            scope: scopes.finished,
            count: count.finished,
            isActive: this.scope === 'finished',
          },
          {
            name: __('Branches'),
            scope: scopes.branches,
            isActive: this.scope === 'branches',
          },
          {
            name: __('Tags'),
            scope: scopes.tags,
            isActive: this.scope === 'tags',
          },
        ];
      },
    },
    created() {
      this.service = new PipelinesService(this.endpoint);
      this.requestData = { page: this.page, scope: this.scope };
    },
    methods: {
      successCallback(resp) {
        return resp.json().then((response) => {
          // Because we are polling & the user is interacting verify if the response received
          // matches the last request made
          if (_.isEqual(parseQueryStringIntoObject(resp.url.split('?')[1]), this.requestData)) {
            this.store.storeCount(response.count);
            this.store.storePagination(resp.headers);
            this.setCommonData(response.pipelines);
          }
        });
      },
      /**
       * Handles URL and query parameter changes.
       * When the user uses the pagination or the tabs,
       *  - update URL
       *  - Make API request to the server with new parameters
       *  - Update the polling function
       *  - Update the internal state
       */
      updateContent(parameters) {
        this.updateInternalState(parameters);

        // fetch new data
        return this.service.getPipelines(this.requestData)
          .then((response) => {
            this.isLoading = false;
            this.successCallback(response);

            // restart polling
            this.poll.restart({ data: this.requestData });
          })
          .catch(() => {
            this.isLoading = false;
            this.errorCallback();

            // restart polling
            this.poll.restart({ data: this.requestData });
          });
      },

      handleResetRunnersCache(endpoint) {
        this.isResetCacheButtonLoading = true;

        this.service.postAction(endpoint)
          .then(() => {
            this.isResetCacheButtonLoading = false;
            createFlash(
              s__('Pipelines|Project cache successfully reset.'),
              'notice',
            );
          })
          .catch(() => {
            this.isResetCacheButtonLoading = false;
            createFlash(s__('Pipelines|Something went wrong while cleaning runners cache.'));
          });
      },
    },
  };
</script>
<template>
  <div class="pipelines-container">
    <div
      class="top-area scrolling-tabs-container inner-page-scroll-tabs"
      v-if="shouldRenderTabs || shouldRenderButtons"
    >
      <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
        v-if="shouldRenderTabs"
        :tabs="tabs"
        @onChangeTab="onChangeTab"
        scope="pipelines"
      />

      <navigation-controls
        v-if="shouldRenderButtons"
        :new-pipeline-path="newPipelinePath"
        :reset-cache-path="resetCachePath"
        :ci-lint-path="ciLintPath"
        @resetRunnersCache="handleResetRunnersCache"
        :is-reset-cache-button-loading="isResetCacheButtonLoading"
      />
    </div>

    <div class="content-list pipelines">

      <loading-icon
        v-if="stateToRender === $options.stateMap.loading"
        :label="s__('Pipelines|Loading Pipelines')"
        size="3"
        class="prepend-top-20"
      />

      <empty-state
        v-else-if="stateToRender === $options.stateMap.emptyState"
        :help-page-path="helpPagePath"
        :empty-state-svg-path="emptyStateSvgPath"
        :can-set-ci="canCreatePipeline"
      />

      <svg-blank-state
        v-else-if="stateToRender === $options.stateMap.error"
        :svg-path="errorStateSvgPath"
        :message="s__(`Pipelines|There was an error fetching the pipelines.
        Try again in a few moments or contact your support team.`)"
      />

      <svg-blank-state
        v-else-if="stateToRender === $options.stateMap.emptyTab"
        :svg-path="noPipelinesSvgPath"
        :message="emptyTabMessage"
      />

      <div
        class="table-holder"
        v-else-if="stateToRender === $options.stateMap.tableList"
      >

        <pipelines-table-component
          :pipelines="state.pipelines"
          :update-graph-dropdown="updateGraphDropdown"
          :auto-devops-help-path="autoDevopsPath"
          :view-type="viewType"
        />
      </div>

      <table-pagination
        v-if="shouldRenderPagination"
        :change="onChangePage"
        :page-info="state.pageInfo"
      />
    </div>
  </div>
</template>