<!--
A data table for the parameters page
-->
<template>
  <div class="container">
    <UiLoadingPanel v-if="pending" />
    <div v-else>
      <LayoutParametersTable
        :items="items"
        :columns-definitions="columns"
        :actions="actions"
        :actions-route="actionsRoute"
        @editClicked="onEditClicked"
        @deleteClicked="onDeleteClicked"
        @addClicked="goToCreatePage"
      />

      <UiFormDeletionConfirmationDialog
        v-model="showDeletionConfirmationDialog"
        @deleteClicked="onDeleteConfirmed"
        @cancelClicked="onCancelClicked"
      />
    </div>
  </div>
</template>

<script setup lang="ts">
import { TABLE_ACTION } from '~/types/enum/enums'
import UrlUtils from '~/services/utils/urlUtils'
import type ApiResource from '~/models/ApiResource'
import { useEntityFetch } from '~/composables/data/useEntityFetch'
import type { AssociativeArray } from '~/types/data'
import type { ColumnDefinition } from '~/types/interfaces'
import {useDeleteItem} from '~/composables/form/useDeleteItem'
import {useEntityManager} from '~/composables/data/useEntityManager';

const props = defineProps({
  /**
   * The model whom entities shall be to fetch
   */
  model: {
    type: Object as PropType<typeof ApiResource>,
    required: true,
  },
  /**
   * If provided, define the columns to show.
   * Else, all the entity's props are shown.
   *
   * Ex: [
   *       { property: 'id', label : 'Identifier'},
   *       { property: 'name', label : 'Full name'},
   *     ]
   */
  columnsDefinitions: {
    type: Array as PropType<Array<ColumnDefinition> | null>,
    required: false,
    default: null,
  },
  /**
   * List of the actions available for each record
   */
  actions: {
    type: Array as PropType<Array<TABLE_ACTION>>,
    required: false,
    default: [TABLE_ACTION.EDIT, TABLE_ACTION.DELETE, TABLE_ACTION.ADD],
  },
  /**
   * The base URL for the edit / create pages
   * The resulting url will be constructed this way :
   *
   * Edition : ({baseUrl}/){apiResource.entity}/{id}
   * Creation : ({baseUrl}/){apiResource.entity}/new
   */
  baseActionsRoute: {
    type: String,
    required: false,
    default: '/parameters',
  },
  /**
   * If provided, sort the record by the given property
   */
  sortBy: {
    type: String as PropType<string>,
    required: false,
    default: 'id',
  },
})

const i18n = useI18n()

const { em } = useEntityManager()

const { fetchCollection } = useEntityFetch()

const { data: collection, pending } = fetchCollection(props.model)

const { deleteItem } = useDeleteItem()

const pageStore = usePageStore()

/**
 * Return the properties to display in the table, or all the
 * props of the model if not specified.
 */
const columns: ComputedRef<Array<ColumnDefinition>> = computed(() => {
  return (
    props.columnsDefinitions ??
    Object.getOwnPropertyNames(new props.model()).map((prop) => {
      return { property: prop }
    })
  )
})

/**
 * Fetch the collection of ApiResources of the given model, then
 * map it according to the configuration.
 */
const items: ComputedRef<Array<ApiResource> | null> = computed(() => {
  if (pending.value || collection.value === null) {
    return null
  }

  let items: Array<ApiResource> = collection.value!.items

  if (props.columnsDefinitions !== null) {
    // Filter the columns to show
    items = items.map((item) => {
      const newItem: ApiResource = { id: item.id }
      for (const col of props.columnsDefinitions!) {
        newItem[col.property] = item[col.property]
      }
      return newItem
    })
  }

  if (props.sortBy) {
    items = items.sort((a: AssociativeArray, b: AssociativeArray) => {
      return a[props.sortBy as keyof typeof a] >
        b[props.sortBy as keyof typeof b]
        ? 1
        : -1
    })
  }

  return items
})

const actionsRoute = computed(() => {
  return UrlUtils.join(props.baseActionsRoute, props.model.entity)
})

const showDeletionConfirmationDialog: Ref<boolean> = ref(false)
const itemToDelete: Ref<ApiResource | null> = ref(null)
/**
 * Redirect to the edition page for the given item
 * @param item
 */
const onEditClicked = (item: ApiResource) => {
  navigateTo(UrlUtils.join(actionsRoute.value, item.id))
}

/**
 * Show the deletion confirmation dialog
 * @param item
 */
const onDeleteClicked = (item: ApiResource) => {
  itemToDelete.value = em.cast(props.model, item)
  showDeletionConfirmationDialog.value = true
}

const onCancelClicked = () => {
  itemToDelete.value = null
}

/**
 * Deletion has be confirmed, perform
 */
const onDeleteConfirmed = async () => {
  pageStore.loading = true
  await deleteItem(itemToDelete.value)
  pageStore.loading = false
}

/**
 * Redirect to the creation page for this model
 */
const goToCreatePage = () => {
  navigateTo(UrlUtils.join(actionsRoute.value, 'new'))
}
</script>

<style scoped lang="scss"></style>
