<template>
  <div class="estimation-wrapper">
    <div class="estimation-helper columns">
      <div
        ref="body"
        class="task-list column datatable-wrapper"
      >
        <table class="datatable">
          <thead class="datatable-head">
            <tr>
              <th class="assignees">
                {{ $t('tasks.fields.assignees') }}
              </th>
              <th class="thumbnail" />
              <th
                v-if="isAssets"
                class="asset-type"
              >
                {{ $t('tasks.fields.asset_type') }}
              </th>
              <th
                v-else
                class="sequence"
              >
                {{ $t('tasks.fields.sequence') }}
              </th>
              <th class="name">
                {{ $t('tasks.fields.entity_name') }}
              </th>
              <th
                v-if="!isAssets"
                class="frames numeric-cell"
              >
                {{ $t('tasks.fields.frames') }}
              </th>
              <th
                v-if="!isAssets"
                class="seconds numeric-cell"
              >
                {{ $t('tasks.fields.seconds').substring(0, 3) }}.
              </th>
              <th class="estimation numeric-cell">
                {{ $t('tasks.fields.estimation').substring(0, 3) }}.
              </th>
            </tr>
          </thead>

          <tbody class="datatable-body">
            <tr
              v-for="(task, index) in tasksByPerson"
              :ref="'task-' + task.id"
              :key="task.id"
              :class="{
                'datatable-row': true,
                selected: selectionGrid[task.id],
                'task-line': true
              }"
            >
              <td class="assignees flexrow">
                <people-avatar
                  v-for="personId in task.assignees"
                  v-if="task.assignees.length > 1"
                  :key="task.id + '-' + personId"
                  class="flexrow-item"
                  :person="personMap.get(personId)"
                  :size="30"
                  :font-size="17"
                  :is-link="false"
                />
                <span
                  v-for="personId in task.assignees"
                  v-else
                  :key="task.id + '-' + personId"
                  class="flexrow"
                >
                  <people-avatar
                    class="flexrow-item"
                    :person="personMap.get(personId)"
                    :size="30"
                    :font-size="17"
                    :is-link="false"
                  />
                  <people-name
                    class="flexrow-item"
                    :person="personMap.get(personId)"
                  />
                </span>
              </td>
              <td class="thumbnail">
                <entity-thumbnail
                  :entity="getEntity(task.entity.id)"
                  :width="50"
                  :height="33"
                  :empty-width="50"
                  :empty-height="31"
                  :with-link="false"
                />
              </td>
              <td
                v-if="isAssets"
                class="asset-type"
              >
                {{ getEntity(task.entity.id).asset_type_name }}
              </td>
              <td
                v-else
                class="sequence"
              >
                {{ getEntity(task.entity.id).sequence_name }}
              </td>
              <td class="name">
                {{ getEntity(task.entity.id).name }}
              </td>
              <td
                v-if="!isAssets"
                class="frames numeric-cell"
              >
                {{ getEntity(task.entity.id).nb_frames }}
              </td>
              <td
                v-if="!isAssets"
                class="frames numeric-cell"
              >
                {{ getSeconds(task) }}
              </td>
              <td
                class="estimation numeric-cell"
                @click="selectTask($event, task, index)"
              >
                <input
                  v-if="isInDepartment(task)"
                  :ref="task.id + '-estimation'"
                  class="input stylehidden"
                  :value="formatDuration(task.estimation)"
                  @blur="onInputBlur"
                  @change="estimationUpdated($event, task, index)"
                  @keydown="onKeyDown"
                  @mouseout="onInputMouseOut"
                  @mouseover="onInputMouseOver"
                >
                <span v-else>
                  {{ formatDuration(task.estimation) }}
                </span>
              </td>
            </tr>
          </tbody>
        </table>
      </div>

      <div class="person-list column datatable-wrapper">
        <table class="datatable">
          <thead
            ref="thead"
            class="datatable-head"
          >
            <tr>
              <th class="assignees">
                {{ $t('tasks.fields.assignees') }}
              </th>
              <th class="count numeric-cell">
                {{ $t('tasks.fields.count') }}
              </th>
              <th class="frames numeric-cell">
                {{ $t('tasks.fields.frames') }}
              </th>
              <th class="seconds numeric-cell">
                {{ $t('tasks.fields.seconds').substring(0, 3) }}.
              </th>
              <th class="estimation numeric-cell">
                {{ $t('tasks.fields.estimation').substring(0, 3) }}.
              </th>
              <th class="quota numeric-cell">
                {{
                  $t('tasks.fields.estimated_quota') +
                    ' ' +
                    $t('tasks.fields.seconds').substring(0, 3)
                }}.
              </th>
              <th class="quota numeric-cell">
                {{
                  $t('tasks.fields.estimated_quota') +
                    ' ' +
                    $t('tasks.fields.frames').substring(0, 3)
                }}.
              </th>
              <th class="quota numeric-cell">
                {{
                  $t('tasks.fields.estimated_quota') +
                    ' ' +
                    $t('tasks.fields.count')
                }}.
              </th>
              <th class="empty">
&nbsp;
              </th>
            </tr>
          </thead>

          <tbody class="datatable-body">
            <tr
              v-for="person in assignees"
              :ref="'person-' + person.id"
              :key="person.id"
              :class="{
                'datatable-row': true,
                'task-line': true
              }"
            >
              <td class="person flexrow">
                <people-avatar
                  class="flexrow-item"
                  :person="person"
                  :size="30"
                  :font-size="17"
                  :is-link="false"
                />
                <people-name
                  class="flexrow-item"
                  :person="person"
                />
              </td>
              <td class="count numeric-cell">
                {{ person.count }}
              </td>
              <td class="frames numeric-cell">
                {{ person.frames }}
              </td>
              <td class="seconds numeric-cell">
                {{ person.seconds }}
              </td>
              <td class="estimation numeric-cell">
                {{ person.estimation }}
              </td>
              <td class="quota numeric-cell">
                {{ person.quota }}
              </td>
              <td class="quota numeric-cell">
                {{ person.quotaFrames }}
              </td>
              <td class="quota numeric-cell">
                {{ person.quotaCount }}
              </td>
              <td />
            </tr>
          </tbody>
        </table>
      </div>
    </div>
  </div>
</template>

<script>
import { mapGetters, mapActions } from 'vuex'

import EntityThumbnail from '@/components/widgets/EntityThumbnail'
import PeopleAvatar from '@/components/widgets/PeopleAvatar'
import PeopleName from '@/components/widgets/PeopleName'

import { domMixin } from '@/components/mixins/dom'
import { formatListMixin } from '@/components/mixins/format'
import { minutesToDays, range } from '@/lib/time'
import { frameToSeconds } from '@/lib/video'
import firstBy from 'thenby'

export default {
  name: 'EstimationHelper',

  mixins: [domMixin, formatListMixin],

  components: {
    EntityThumbnail,
    PeopleAvatar,
    PeopleName
  },

  props: {
    entityType: {
      type: String,
      default: 'Asset'
    },
    tasks: {
      type: Array,
      default: () => []
    }
  },

  data() {
    return {
      lastSelection: 0,
      lastShiftSelection: 0,
      selectionGrid: {}
    }
  },

  mounted() {},

  computed: {
    ...mapGetters([
      'assetMap',
      'editMap',
      'currentProduction',
      'isCurrentUserManager',
      'isCurrentUserSupervisor',
      'user',
      'organisation',
      'personMap',
      'shotMap',
      'taskTypeMap'
    ]),

    isAssets() {
      return this.entityType === 'Asset'
    },

    assignees() {
      const assigneeSet = new Set()
      const countMap = new Map()
      const secondMap = new Map()
      const frameMap = new Map()
      const estimationMap = new Map()
      const assignees = []
      this.tasks.forEach((task) => {
        const entity = this.getEntity(task.entity_id)
        task.assignees.forEach((personId) => {
          assigneeSet.add(personId)
          countMap.set(personId, (countMap.get(personId) || 0) + 1)
          estimationMap.set(
            personId,
            (estimationMap.get(personId) || 0) + task.estimation
          )
          if (!this.isAssets) {
            const frames = entity.nb_frames || 0
            const seconds = frameToSeconds(
              frames,
              this.currentProduction,
              entity
            )
            secondMap.set(personId, (secondMap.get(personId) || 0) + seconds)
            frameMap.set(personId, (frameMap.get(personId) || 0) + frames)
          }
        })
      })
      assigneeSet.forEach((val, personId) =>
        assignees.push(this.personMap.get(personId))
      )
      return assignees.sort(firstBy('name')).map((person) => {
        const estimation = estimationMap.get(person.id) || 0
        const seconds = secondMap.get(person.id) || 0
        const frames = frameMap.get(person.id) || 0
        const count = countMap.get(person.id) || 0
        const estimationDays = minutesToDays(this.organisation, estimation)
        const quota = estimation > 0 ? seconds / estimationDays : 0
        const quotaCount = estimation > 0 ? count / estimationDays : 0
        const quotaFrames = estimation > 0 ? frames / estimationDays : 0
        return {
          ...person,
          count: countMap.get(person.id) || 0,
          estimation: this.formatDuration(estimation),
          frames,
          quota: quota.toFixed(2),
          quotaFrames: quotaFrames.toFixed(2),
          quotaCount: quotaCount.toFixed(2),
          seconds: seconds.toFixed(2)
        }
      })
    },

    tasksByPerson() {
      return [...this.tasks].sort(firstBy(this.compareFirstAssignees))
    }
  },

  methods: {
    ...mapActions(['updateTask']),

    frameToSeconds,

    getEntity(entityId) {
      if (this.isAssets) {
        return this.assetMap.get(entityId)
      } else if (this.entityType === 'Shot') {
        return this.shotMap.get(entityId)
      } else if (this.entityType === 'Edit') {
        return this.editMap.get(entityId)
      }
      return this.assetMap.get(entityId)
    },

    compareFirstAssignees(a, b) {
      if (a.assignees.length > 0 && b.assignees.length > 0) {
        const personA = this.personMap.get(a.assignees[0])
        const personB = this.personMap.get(b.assignees[0])
        return personA.name.localeCompare(personB.name)
      } else if (a.assignees.length > 0) {
        return -1
      } else if (b.assignees.length > 0) {
        return 1
      } else {
        return -1
      }
    },

    getSeconds(task) {
      const shot = this.getEntity(task.entity_id)
      return frameToSeconds(shot.nb_frames, this.currentProduction, shot)
    },

    estimationUpdated(event, task) {
      const value = event.target.value
      if (value && value.length > 0) {
        const estimation = parseFloat(event.target.value)
        this.saveEstimations(estimation, task)
      }
    },

    saveEstimations(days, task) {
      const selection = Object.keys(this.selectionGrid)
      if (selection.length > 1) {
        selection.forEach((taskId) => {
          this.$emit('estimation-changed', { taskId, days })
        })
      } else {
        this.$emit('estimation-changed', { taskId: task.id, days })
      }
    },

    onKeyDown(event) {
      if (event.key === 'Tab') {
        this.pauseEvent(event)
        if (event.shiftKey) {
          this.selectPrevious()
        } else {
          this.selectNext()
        }
      } else if (event.key === 'ArrowDown') {
        this.pauseEvent(event)
        this.selectNext(event.shiftKey)
      } else if (event.key === 'ArrowUp') {
        this.pauseEvent(event)
        this.selectPrevious(event.shiftKey)
      }
    },

    clearSelection() {
      this.selectionGrid = {}
    },

    addToSelection(taskId) {
      this.selectionGrid[taskId] = true
    },

    selectTask(event, task, index) {
      if (event.shiftKey) {
        if (!(event.ctrlKey || event.metaKey)) this.clearSelection()
        this.selectTaskRange(index)
      } else {
        if (!(event.ctrlKey || event.metaKey)) this.clearSelection()
        this.selectSingleTask(index)
      }
      if (this.isInDepartment(task)) {
        this.focusInput(
          this.$refs[this.tasksByPerson[index].id + '-estimation'][0]
        )
      }
    },

    selectPrevious(shiftKey) {
      let index = this.lastSelection
      index = index - 1 < 0 ? this.tasksByPerson.length - 1 : index - 1
      this.selectTask({ shiftKey }, this.tasksByPerson[index], index)
    },

    selectNext(shiftKey) {
      let index = this.lastSelection
      index = index + 1 >= this.tasksByPerson.length ? 0 : index + 1
      this.selectTask({ shiftKey }, this.tasksByPerson[index], index)
    },

    selectSingleTask(index) {
      const task = this.tasksByPerson[index]
      this.addToSelection(task.id)
      this.lastSelection = index
      this.lastShiftSelection = index
    },

    selectTaskRange(index) {
      let taskIndices = []
      this.lastSelection = index
      if (this.lastShiftSelection > index) {
        taskIndices = range(index, this.lastShiftSelection)
      } else {
        taskIndices = range(this.lastShiftSelection, index)
      }
      const selection = taskIndices.map((i) => this.tasksByPerson[i].id)
      selection.forEach((taskId) => {
        this.addToSelection(taskId)
      })
    },

    isInDepartment(task) {
      if (this.isCurrentUserManager) {
        return true
      } else if (this.isCurrentUserSupervisor) {
        if (this.user.departments.length === 0) {
          return true
        } else {
          const taskType = this.taskTypeMap.get(task.task_type_id)
          return (
            taskType.department_id &&
            this.user.departments.includes(taskType.department_id)
          )
        }
      } else {
        return false
      }
    }
  }
}
</script>

<style lang="scss" scoped>
th {
  padding: 0.4em 0;
}

td {
  padding: 0 0.4em;

  &.thumbnail {
    padding-top: 0.2em;
  }

  &.assignees {
    padding-left: 0.4em;
    padding-top: 0.2em;
  }
}

.assignees {
  min-width: 200px;
  max-width: 200px;
  width: 200px;

  span {
    margin-top: 0.2em;
    margin-bottom: 0.2em;
  }
}

.thumbnail {
  min-width: 64px;
  max-width: 64px;
  width: 64px;
}

.asset-type {
  min-width: 120px;
  width: 120px;
}

.sequence {
  min-width: 120px;
  width: 120px;
}

.name {
  min-width: 120px;
  width: 120px;
  font-weight: bold;
}

.frames,
.estimation,
.seconds,
.count {
  min-width: 60px;
  width: 60px;
}

.number {
  min-width: 80px;
  width: 80px;
  text-align: right;
}

.estimation-helper {
  max-height: 100%;
}

.estimation-wrapper {
  flex: 1;
}

.columns {
  margin-top: 1em;
}

.column {
  padding: 0 1em 1em 1em;
}

.task-list {
  .empty {
    border-left: 0px solid transparent;
  }
}

th.numeric-cell {
  padding-right: 0.4em;
}

.numeric-cell {
  text-align: right;

  input {
    text-align: right;
  }
}

.person-list {
  flex: 1;

  td {
    padding: 0.2em;
  }
}
</style>
