<template>
  <v-card>
    <v-card-title class="title">
      <span v-if="isTutor">Your</span><span>All</span>&nbsp;feedback history
      <v-spacer/>
      <v-text-field
        append-icon="search"
        label="Search"
        single-line
        hide-details
        v-model="search"
      />
    </v-card-title>
    <feedback-search-options class="mx-3"/>
    <v-data-table
      :headers="headers"
      :items="feedback"
      :search="search"
      :custom-filter="searchFunction"
      :filter="containsSearch"
      hide-actions
    >
      <template slot="items" slot-scope="props">
        <tr @click="showSubmission(props.item.ofSubmission)"
            class="feedback-row"
        >
          <td>{{props.item.ofSubmissionType}}</td>
          <td>{{props.item.score}}</td>
          <td>{{new Date(props.item.created).toLocaleString()}}</td>
          <td>
            <v-icon v-if="props.item.isFinal">check</v-icon>
            <v-icon v-else>clear</v-icon>
          </td>
        </tr>
      </template>
    </v-data-table>
  </v-card>
</template>

<script lang="ts">
import Vue from 'vue'
import { mapState, mapGetters } from 'vuex'
import Component from 'vue-class-component'
import { getObjectValueByPath } from '@/util/helpers'
import FeedbackSearchOptions from '@/components/feedback_list/FeedbackSearchOptions.vue'
import { FeedbackSearchOptions as OptionsModule } from '@/store/modules/feedback_list/feedback-search-options'
import { FeedbackTable as FeedbackModule, FeedbackHistoryItem } from '@/store/modules/feedback_list/feedback-table'
import { Subscription, Feedback } from '@/models'
import { actions } from '@/store/actions'
import { getters } from '@/store/getters'
import { Authentication } from '../../store/modules/authentication';

@Component({
  components: {
    FeedbackSearchOptions
  }
})
export default class FeedbackTable extends Vue {
  get showFinal () { return OptionsModule.state.showFinal }
  get searchOtherUserComments () { return OptionsModule.state.searchOtherUserComments }
  get caseSensitive () { return OptionsModule.state.caseSensitive }
  get useRegex () { return OptionsModule.state.useRegex }
  get filterByTutors () { return OptionsModule.state.filterByTutors }
  get filterByStage () { return OptionsModule.state.filterByStage }
  get isTutor () { return Authentication.isTutor }

  get stageFilterString () { return OptionsModule.stageFilterString }

  get feedback () {
    return Object.values(FeedbackModule.state.feedbackHist).filter(feedback => {
      return this.checkFinal(feedback) && this.filterFeedbackByTutorStage(feedback)
    })
  }

  search = ''
  prefetchWhenLessItems = 11
  headers = [
    {
      text: 'Type',
      align: 'left',
      value: 'ofSubmissionType'
    },
    {
      text: 'score',
      value: 'score'
    },
    {
      text: 'Created',
      value: 'created'
    },
    {
      text: 'Final',
      value: 'final'
    }
  ]

  filterFeedbackByTutorStage (feedback: FeedbackHistoryItem) {
    if (!feedback.history) {
      // if feedback is not filtered by tutor or stage return true, otherwise false
      return this.filterByTutors.length === 0
    }
    const associatedTutors = this.stageFilterString === 'all'
      ? Object.values(feedback.history).filter(histEntry => !!histEntry).map(histEntry => histEntry!.owner)
      : feedback.history[<Subscription.FeedbackStageEnum> this.stageFilterString]
        ? [feedback.history[<Subscription.FeedbackStageEnum> this.stageFilterString]!.owner] : []
    return this.filterByTutors.length === 0 ||
        associatedTutors.some(tutor => this.filterByTutors.includes(tutor))
  }
  showSubmission (submissionPk: string) {
    this.$router.push(`/feedback/${submissionPk}`)
  }
  prefetchSubmission (submissionPk: string) {
    actions.getSubmissionFeedbackTest({ pk: submissionPk })
  }
  prefetchFilteredItems (items: Feedback[]) {
    if (items.length < this.prefetchWhenLessItems) {
      for (let item of items) {
        if (item.ofSubmission && !getters.state.submissions[item.ofSubmission]) {
          this.prefetchSubmission(item.ofSubmission)
        }
      }
    }
  }
  containsSearch (val: {toString: () => string}, search: string | RegExp) {
    if (!val || typeof val === 'boolean') {
      return false
    }
    if (search instanceof RegExp) {
      return search.test(val.toString())
    }
    if (this.caseSensitive) {
      return val.toString().indexOf(search) !== -1
    } else {
      return val.toString().toLowerCase().indexOf(search.toLowerCase()) !== -1
    }
  }
  checkFinal (feedback: Feedback) {
    return this.showFinal ? true : !feedback.isFinal
  }
  commentFilter (feedback: Feedback, search: string | RegExp, filter: any) {
    return Object.values(feedback.feedbackLines || {}).some(line => line.some(comment => {
      return filter(comment.text, search)
    }))
  }
  searchFunction (items: Feedback[], search: string, filter: any) {
    if (search.trim() === '') return items
    const props = this.headers.map(h => h.value)
    const searchVal = this.useRegex ? new RegExp(search, this.caseSensitive ? 'u' : 'iu') : search
    let filteredItems = items.filter(feedback => {
      return props.some(prop => filter(getObjectValueByPath(feedback, prop), searchVal) ||
          this.commentFilter(feedback, searchVal, filter))
    })
    this.prefetchFilteredItems(filteredItems)
    return filteredItems
  }
}
</script>

<style scoped>
  .feedback-row {
    cursor: pointer;
  }
</style>