<script>
import { s__, __ } from '~/locale';
import { GlEmptyState, GlFormCheckbox, GlLink, GlSkeletonLoading, GlTable } from '@gitlab/ui';
import RemediatedBadge from './remediated_badge.vue';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import SelectionSummary from 'ee/security_dashboard/components/selection_summary.vue';
import { VULNERABILITIES_PER_PAGE } from '../constants';

export default {
  name: 'VulnerabilityList',
  components: {
    GlEmptyState,
    GlFormCheckbox,
    GlLink,
    GlSkeletonLoading,
    GlTable,
    RemediatedBadge,
    SelectionSummary,
    SeverityBadge,
  },
  props: {
    dashboardDocumentation: {
      type: String,
      required: true,
    },
    emptyStateSvgPath: {
      type: String,
      required: true,
    },
    filters: {
      type: Object,
      required: false,
      default: null,
    },
    shouldShowSelection: {
      type: Boolean,
      required: false,
      default: false,
    },
    vulnerabilities: {
      type: Array,
      required: true,
    },
    isLoading: {
      type: Boolean,
      required: false,
      default: false,
    },
    shouldShowProjectNamespace: {
      type: Boolean,
      required: false,
      default: false,
    },
  },
  data() {
    return {
      selectedVulnerabilities: {},
    };
  },
  computed: {
    hasSelectedAllVulnerabilities() {
      return this.numOfSelectedVulnerabilities === this.vulnerabilities.length;
    },
    numOfSelectedVulnerabilities() {
      return Object.keys(this.selectedVulnerabilities).length;
    },
    shouldShowSelectionSummary() {
      return this.shouldShowSelection && Boolean(this.numOfSelectedVulnerabilities);
    },
    checkboxClass() {
      return this.shouldShowSelection ? '' : 'd-none';
    },
    fields() {
      const commonThClass = ['table-th-transparent', 'original-gl-th'].join(' ');
      return [
        {
          key: 'checkbox',
          class: this.checkboxClass,
          thClass: commonThClass,
        },
        {
          key: 'state',
          label: s__('Vulnerability|Status'),
          thClass: `gl-w-64 ${commonThClass}`,
        },
        {
          key: 'severity',
          label: s__('Vulnerability|Severity'),
          thClass: `gl-w-64 ${commonThClass}`,
        },
        {
          key: 'title',
          label: __('Description'),
          thClass: commonThClass,
        },
      ];
    },
  },
  watch: {
    filters() {
      this.selectedVulnerabilities = {};
    },
    vulnerabilities(vulnerabilities) {
      const ids = new Set(vulnerabilities.map(v => v.id));

      Object.keys(this.selectedVulnerabilities).forEach(vulnerabilityId => {
        if (!ids.has(vulnerabilityId)) {
          this.$delete(this.selectedVulnerabilities, vulnerabilityId);
        }
      });
    },
  },
  methods: {
    deselectAllVulnerabilities() {
      this.selectedVulnerabilities = {};
    },
    isSelected(vulnerability = {}) {
      return Boolean(this.selectedVulnerabilities[vulnerability.id]);
    },
    selectAllVulnerabilities() {
      this.selectedVulnerabilities = this.vulnerabilities.reduce((acc, curr) => {
        acc[curr.id] = curr;
        return acc;
      }, {});
    },
    shouldShowVulnerabilityPath(item) {
      return Boolean(item.location.image || item.location.file);
    },
    toggleAllVulnerabilities() {
      if (this.hasSelectedAllVulnerabilities) {
        this.deselectAllVulnerabilities();
      } else {
        this.selectAllVulnerabilities();
      }
    },
    toggleVulnerability(vulnerability) {
      if (!vulnerability) return;

      if (this.selectedVulnerabilities[vulnerability.id]) {
        this.$delete(this.selectedVulnerabilities, `${vulnerability.id}`);
      } else {
        this.$set(this.selectedVulnerabilities, `${vulnerability.id}`, vulnerability);
      }
    },
  },
  VULNERABILITIES_PER_PAGE,
};
</script>

<template>
  <div>
    <selection-summary
      v-if="shouldShowSelectionSummary"
      :selected-vulnerabilities="Object.values(selectedVulnerabilities)"
      @deselect-all-vulnerabilities="deselectAllVulnerabilities"
      @refetch-vulnerabilities="$emit('refetch-vulnerabilities')"
    />
    <gl-table
      :busy="isLoading"
      :fields="fields"
      :items="vulnerabilities"
      stacked="sm"
      show-empty
      responsive
    >
      <template #head(checkbox)>
        <gl-form-checkbox
          :checked="hasSelectedAllVulnerabilities"
          @change="toggleAllVulnerabilities"
        />
      </template>

      <template #cell(checkbox)="{ item }">
        <gl-form-checkbox :checked="isSelected(item)" @change="toggleVulnerability(item)" />
      </template>

      <template #cell(state)="{ item }">
        <span class="text-capitalize js-status">{{ item.state.toLowerCase() }}</span>
      </template>

      <template #cell(severity)="{ item }">
        <severity-badge class="js-severity" :severity="item.severity" />
      </template>

      <template #cell(title)="{ item }">
        <gl-link class="text-body js-description" :href="item.vulnerabilityPath">
          {{ item.title }}
        </gl-link>
        <div
          v-if="item.location"
          :data-testid="`location-${item.id}`"
          class="gl-text-color-secondary gl-font-sm"
        >
          <div v-if="shouldShowProjectNamespace">
            {{ item.project.nameWithNamespace }}
          </div>
          <div v-if="shouldShowVulnerabilityPath(item)" class="monospace">
            {{ item.location.image || item.location.file }}
          </div>
        </div>
        <remediated-badge v-if="item.resolved_on_default_branch" class="ml-2" />
      </template>

      <template #table-busy>
        <gl-skeleton-loading
          v-for="n in $options.VULNERABILITIES_PER_PAGE"
          :key="n"
          class="m-2 js-skeleton-loader"
          :lines="2"
        />
      </template>

      <template #empty>
        <slot name="emptyState">
          <gl-empty-state
            :title="s__(`We've found no vulnerabilities`)"
            :description="
              __(
                `While it's rare to have no vulnerabilities, it can happen. In any event, we ask that you please double check your settings to make sure you've set up your dashboard correctly.`,
              )
            "
          />
        </slot>
      </template>
    </gl-table>
  </div>
</template>
