<script>
import {
  GlButton,
  GlDropdown,
  GlDropdownItem,
  GlModal,
  GlModalDirective,
  GlLink,
} from '@gitlab/ui';
import _ from 'underscore';
import { mapActions, mapState } from 'vuex';
import { s__ } from '~/locale';
import Icon from '~/vue_shared/components/icon.vue';
import '~/vue_shared/mixins/is_ee';
import { getParameterValues } from '~/lib/utils/url_utility';
import MonitorAreaChart from './charts/area.vue';
import GraphGroup from './graph_group.vue';
import EmptyState from './empty_state.vue';
import { timeWindows, timeWindowsKeyNames } from '../constants';
import { getTimeDiff } from '../utils';

const sidebarAnimationDuration = 150;
let sidebarMutationObserver;

export default {
  components: {
    MonitorAreaChart,
    GraphGroup,
    EmptyState,
    Icon,
    GlButton,
    GlDropdown,
    GlDropdownItem,
    GlLink,
    GlModal,
  },
  directives: {
    GlModalDirective,
  },
  props: {
    externalDashboardUrl: {
      type: String,
      required: false,
      default: '',
    },
    hasMetrics: {
      type: Boolean,
      required: false,
      default: true,
    },
    showPanels: {
      type: Boolean,
      required: false,
      default: true,
    },
    documentationPath: {
      type: String,
      required: true,
    },
    settingsPath: {
      type: String,
      required: true,
    },
    clustersPath: {
      type: String,
      required: true,
    },
    tagsPath: {
      type: String,
      required: true,
    },
    projectPath: {
      type: String,
      required: true,
    },
    metricsEndpoint: {
      type: String,
      required: true,
    },
    deploymentEndpoint: {
      type: String,
      required: false,
      default: null,
    },
    emptyGettingStartedSvgPath: {
      type: String,
      required: true,
    },
    emptyLoadingSvgPath: {
      type: String,
      required: true,
    },
    emptyNoDataSvgPath: {
      type: String,
      required: true,
    },
    emptyUnableToConnectSvgPath: {
      type: String,
      required: true,
    },
    environmentsEndpoint: {
      type: String,
      required: true,
    },
    currentEnvironmentName: {
      type: String,
      required: true,
    },
    showTimeWindowDropdown: {
      type: Boolean,
      required: true,
    },
    customMetricsAvailable: {
      type: Boolean,
      required: false,
      default: false,
    },
    customMetricsPath: {
      type: String,
      required: true,
    },
    validateQueryPath: {
      type: String,
      required: true,
    },
  },
  data() {
    return {
      state: 'gettingStarted',
      elWidth: 0,
      selectedTimeWindow: '',
      selectedTimeWindowKey: '',
      formIsValid: null,
    };
  },
  computed: {
    canAddMetrics() {
      return this.customMetricsAvailable && this.customMetricsPath.length;
    },
    ...mapState('monitoringDashboard', [
      'groups',
      'emptyState',
      'showEmptyState',
      'environments',
      'deploymentData',
    ]),
  },
  created() {
    this.setEndpoints({
      metricsEndpoint: this.metricsEndpoint,
      environmentsEndpoint: this.environmentsEndpoint,
      deploymentsEndpoint: this.deploymentEndpoint,
    });

    this.timeWindows = timeWindows;
    this.selectedTimeWindowKey =
      _.escape(getParameterValues('time_window')[0]) || timeWindowsKeyNames.eightHours;

    // Set default time window if the selectedTimeWindowKey is bogus
    if (!Object.keys(this.timeWindows).includes(this.selectedTimeWindowKey)) {
      this.selectedTimeWindowKey = timeWindowsKeyNames.eightHours;
    }

    this.selectedTimeWindow = this.timeWindows[this.selectedTimeWindowKey];
  },
  beforeDestroy() {
    if (sidebarMutationObserver) {
      sidebarMutationObserver.disconnect();
    }
  },
  mounted() {
    if (!this.hasMetrics) {
      this.setGettingStartedEmptyState();
    } else {
      this.fetchData(getTimeDiff(this.timeWindows.eightHours));

      sidebarMutationObserver = new MutationObserver(this.onSidebarMutation);
      sidebarMutationObserver.observe(document.querySelector('.layout-page'), {
        attributes: true,
        childList: false,
        subtree: false,
      });
    }
  },
  methods: {
    ...mapActions('monitoringDashboard', [
      'fetchData',
      'setGettingStartedEmptyState',
      'setEndpoints',
    ]),
    getGraphAlerts(queries) {
      if (!this.allAlerts) return {};
      const metricIdsForChart = queries.map(q => q.metricId);
      return _.pick(this.allAlerts, alert => metricIdsForChart.includes(alert.metricId));
    },
    getGraphAlertValues(queries) {
      return Object.values(this.getGraphAlerts(queries));
    },
    hideAddMetricModal() {
      this.$refs.addMetricModal.hide();
    },
    onSidebarMutation() {
      setTimeout(() => {
        this.elWidth = this.$el.clientWidth;
      }, sidebarAnimationDuration);
    },
    setFormValidity(isValid) {
      this.formIsValid = isValid;
    },
    submitCustomMetricsForm() {
      this.$refs.customMetricsForm.submit();
    },
    activeTimeWindow(key) {
      return this.timeWindows[key] === this.selectedTimeWindow;
    },
    setTimeWindowParameter(key) {
      return `?time_window=${key}`;
    },
  },
  addMetric: {
    title: s__('Metrics|Add metric'),
    modalId: 'add-metric',
  },
};
</script>

<template>
  <div v-if="!showEmptyState" class="prometheus-graphs">
    <div class="gl-p-3 border-bottom bg-gray-light d-flex justify-content-between">
      <div
        v-if="environmentsEndpoint"
        class="dropdowns d-flex align-items-center justify-content-between"
      >
        <div class="d-flex align-items-center">
          <strong>{{ s__('Metrics|Environment') }}</strong>
          <gl-dropdown
            class="prepend-left-10 js-environments-dropdown"
            toggle-class="dropdown-menu-toggle"
            :text="currentEnvironmentName"
            :disabled="environments.length === 0"
          >
            <gl-dropdown-item
              v-for="environment in environments"
              :key="environment.id"
              :active="environment.name === currentEnvironmentName"
              active-class="is-active"
              >{{ environment.name }}</gl-dropdown-item
            >
          </gl-dropdown>
        </div>
        <div v-if="showTimeWindowDropdown" class="d-flex align-items-center prepend-left-8">
          <strong>{{ s__('Metrics|Show last') }}</strong>
          <gl-dropdown
            class="prepend-left-10 js-time-window-dropdown"
            toggle-class="dropdown-menu-toggle"
            :text="selectedTimeWindow"
          >
            <gl-dropdown-item
              v-for="(value, key) in timeWindows"
              :key="key"
              :active="activeTimeWindow(key)"
              ><gl-link :href="setTimeWindowParameter(key)">{{ value }}</gl-link></gl-dropdown-item
            >
          </gl-dropdown>
        </div>
      </div>
      <div class="d-flex">
        <div v-if="isEE && canAddMetrics">
          <gl-button
            v-gl-modal-directive="$options.addMetric.modalId"
            class="js-add-metric-button text-success border-success"
          >
            {{ $options.addMetric.title }}
          </gl-button>
          <gl-modal
            ref="addMetricModal"
            :modal-id="$options.addMetric.modalId"
            :title="$options.addMetric.title"
          >
            <form ref="customMetricsForm" :action="customMetricsPath" method="post">
              <custom-metrics-form-fields
                :validate-query-path="validateQueryPath"
                form-operation="post"
                @formValidation="setFormValidity"
              />
            </form>
            <div slot="modal-footer">
              <gl-button @click="hideAddMetricModal">
                {{ __('Cancel') }}
              </gl-button>
              <gl-button
                :disabled="!formIsValid"
                variant="success"
                @click="submitCustomMetricsForm"
              >
                {{ __('Save changes') }}
              </gl-button>
            </div>
          </gl-modal>
        </div>
        <gl-button
          v-if="externalDashboardUrl.length"
          class="js-external-dashboard-link prepend-left-8"
          variant="primary"
          :href="externalDashboardUrl"
          target="_blank"
        >
          {{ __('View full dashboard') }}
          <icon name="external-link" />
        </gl-button>
      </div>
    </div>
    <graph-group
      v-for="(groupData, index) in groups"
      :key="index"
      :name="groupData.group"
      :show-panels="showPanels"
    >
      <monitor-area-chart
        v-for="(graphData, graphIndex) in groupData.metrics"
        :key="graphIndex"
        :graph-data="graphData"
        :deployment-data="deploymentData"
        :thresholds="getGraphAlertValues(graphData.queries)"
        :container-width="elWidth"
        group-id="monitor-area-chart"
      >
        <alert-widget
          v-if="isEE && prometheusAlertsAvailable && alertsEndpoint && graphData"
          :alerts-endpoint="alertsEndpoint"
          :relevant-queries="graphData.queries"
          :alerts-to-manage="getGraphAlerts(graphData.queries)"
          @setAlerts="setAlerts"
        />
      </monitor-area-chart>
    </graph-group>
  </div>
  <empty-state
    v-else
    :selected-state="emptyState"
    :documentation-path="documentationPath"
    :settings-path="settingsPath"
    :clusters-path="clustersPath"
    :empty-getting-started-svg-path="emptyGettingStartedSvgPath"
    :empty-loading-svg-path="emptyLoadingSvgPath"
    :empty-no-data-svg-path="emptyNoDataSvgPath"
    :empty-unable-to-connect-svg-path="emptyUnableToConnectSvgPath"
  />
</template>