<script setup>
import { computed, ref, useTemplateRef } from 'vue'
import { getCollection, postCollectionChangePosition, deleteCollectionItem } from './api.js'
import CollectionFormElement from './CollectionFormElement.vue'
import AddBookToCollection from './AddBookToCollection.vue'
import Pagination from './Pagination.vue'

const props = defineProps({
  id: String,
})

const limit = 5
const pageNumber = ref(1)

const offset = computed(() => (pageNumber.value - 1) * limit)

const data = ref(null)
const error = ref(null)

const itemRefs = useTemplateRef('items')

const itemIdBeingGrabbed = ref(null)

const itemIdBeingOvered = ref(null)

let totalElementsNumber = computed(() =>
  typeof data != 'undefined' && data.value != null ? data.value['count'] : 0,
)

let pageTotal = computed(() => Math.ceil(totalElementsNumber.value / limit))

getCollection(data, error, props.id, limit, offset.value)

function pageChange(newPageNumber) {
  pageNumber.value = newPageNumber
  data.value = null
  error.value = null
  getCollection(data, error, props.id, limit, offset.value)
}

function fetchCollection() {
  pageChange(1)
}

function checkGrabbedPosition(itemId, y) {
  const itemBeingMoved = itemRefs.value.find((it) => it.id == itemId)
  const itemMovedY = itemBeingMoved.$el.offsetTop + y + itemBeingMoved.$el.offsetHeight / 2
  itemRefs.value.forEach((it) => {
    if (it.$props.id == itemIdBeingGrabbed.value) {
      return
    }
    let lowerDetectionY = it.$el.offsetTop + it.$el.offsetHeight / 2
    let upperDetectionY = it.$el.offsetTop + (3 * it.$el.offsetHeight) / 2
    if (it.$props.position < itemBeingMoved.$props.position) {
      lowerDetectionY = it.$el.offsetTop
      upperDetectionY = it.$el.offsetTop + it.$el.offsetHeight / 2
    }
    if (lowerDetectionY < itemMovedY && itemMovedY < upperDetectionY) {
      itemIdBeingOvered.value = it.$props.id
    }
  })
}

function onStopGrab() {
  if (itemIdBeingOvered.value != null) {
    const position = data.value.items.find((it) => it.id == itemIdBeingOvered.value).position
    changePosition(itemIdBeingGrabbed.value, position)
  }
  itemIdBeingGrabbed.value = null
  itemIdBeingOvered.value = null
}

function isDragoverFromAbove(position) {
  if (itemIdBeingGrabbed.value == null) {
    return false
  }
  const grabbedItemPosition = data.value.items.find(
    (it) => it.id == itemIdBeingGrabbed.value,
  ).position
  return position > grabbedItemPosition
}

function changePosition(id, position) {
  postCollectionChangePosition(props.id, id, position).then((res) => {
    if (res.ok) {
      getCollection(data, error, props.id, limit, offset.value)
    } else {
      res.json().then((json) => {
        error.value = json
      })
    }
  })
}

function deleteItem(id) {
  deleteCollectionItem(id).then((res) => {
    if (res.ok) {
      getCollection(data, error, props.id, limit, offset.value)
    } else {
      res.json().then((json) => {
        error.value = json
      })
    }
  })
}
</script>

<template>
  <div v-if="error">{{ $t('collection.error', { error: error }) }}</div>
  <div v-if="data">
    <h2 class="title">{{ data.name }}</h2>
    <AddBookToCollection :collection-id="props.id" @created="fetchCollection" />
    <TransitionGroup name="list" tag="div">
      <CollectionFormElement
        @positionchange="(pos) => changePosition(item.id, pos)"
        @startgrab="itemIdBeingGrabbed = item.id"
        @grabbing="(y) => checkGrabbedPosition(item.id, y)"
        @stopgrab="onStopGrab"
        @delete="deleteItem(item.id)"
        v-for="item in data.items"
        :key="item.id"
        v-bind="item"
        ref="items"
        :is-dragover="item.id == itemIdBeingOvered"
        :is-dragover-from-above="isDragoverFromAbove(item.position)"
      />
    </TransitionGroup>
    <Pagination
      class="mt-5"
      :pageNumber="pageNumber"
      :pageTotal="pageTotal"
      maxItemDisplayed="11"
      @pageChange="pageChange"
    />
  </div>
</template>

<style scoped>
.list-move, /* apply transition to moving elements */
.list-enter-active,
.list-leave-active {
  transition: all 0.2s ease;
}

.list-enter-from,
.list-leave-to {
  opacity: 0;
  transform: translateX(30px);
}
</style>
