<!--
A data table for the parameters page
-->
<template>
  <div class="container">
    <UiLoadingPanel v-if="pending" />
    <v-table v-else>
      <thead>
        <tr>
          <td v-for="col in columns">
            {{ col.label }}
          </td>
          <td>{{ i18n.t('actions') }}</td>
        </tr>
      </thead>
      <tbody v-if="items">
        <tr
          v-for="(item, i) in items"
          :key="i"
        >
          <td
            v-for="col in columns"
            class="cycle-editable-cell"
          >
            {{ item[col.property] }}
          </td>

          <td class="d-flex flex-row actions-cell">
            <v-btn
              v-if="actions.includes(TABLE_ACTION.EDIT)"
              :flat="true"
              icon="fa fa-pen"
              class="mr-3"
              @click="goToEditPage(item.id as number)"
            />
            <UiButtonDelete
              v-if="actions.includes(TABLE_ACTION.DELETE)"
              :entity="item"
              :flat="true"
            />
          </td>
        </tr>
      </tbody>
      <tbody v-else>
        <tr class="theme-neutral">
          <td>
            <i>{{ i18n.t('nothing_to_show') }}</i>
          </td>
          <td></td>
        </tr>
      </tbody>
    </v-table>
    <div class="d-flex justify-end" v-if="actions.includes(TABLE_ACTION.ADD)">
      <v-btn
        :flat="true"
        prepend-icon="fa fa-plus"
        class="theme-primary mt-4"
        @click="goToCreatePage"
      >
        {{ i18n.t('add') }}
      </v-btn>
    </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';

interface ColumnDefinition {
  /**
   * The entity's property to display in this column
   */
  property: string,
  /**
   * Label of the column.
   * If not provided, a translation of the property's name will be looked for.
   * If none is found, the property's name will be displayed as it is.
   */
  label?: string
}

const props = defineProps({
  /**
   * The model whom entities shall be to fetch
   */
  model: {
    type: Object as PropType<typeof ApiResource>,
    required: true
  },
  /**
   * 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
   */
  baseRoute: {
    type: String,
    required: false,
    default: '/parameters'
  },
  /**
   * 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]
  },
  /**
   * If provided, sort the record by the given property
   */
  sortBy: {
    type: String as PropType<string>,
    required: false,
    default: 'id'
  }
})

const i18n = useI18n()

const { fetchCollection } = useEntityFetch()

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

/**
 * Return the properties to display in the table, or all the
 * props of the model if not specified.
 */
const columns: ComputedRef<Array<ColumnDefinition>> = computed(() => {
  let columns: Array<ColumnDefinition>

  if (!props.columnsDefinitions) {
    const entityProps = Object.getOwnPropertyNames(new props.model())

    columns = entityProps.map(prop => {
      return {
        property: prop,
        label: i18n.t(prop)
      }
    })
  } else {
    columns = props.columnsDefinitions

    columns = columns.map(col => {
      return {
        property: col.property,
        label: col.label ?? i18n.t(col.property)
      }
    })
  }

  return columns
})

/**
 * 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
})

/**
 * Redirect to the edition page for the given item
 * @param id
 */
const goToEditPage = (id: number) => {
  console.log(props.baseRoute, props.model.entity, id, UrlUtils.join(props.baseRoute, props.model.entity, id))
  navigateTo(UrlUtils.join(props.baseRoute, props.model.entity, id))
}

/**
 * Redirect to the creation page for this model
 */
const goToCreatePage = () => {
  navigateTo(UrlUtils.join(props.baseRoute, props.model.entity, 'new'))
}

</script>

<style scoped lang="scss">
.container {
  max-width: 1000px;
}

.v-table {
  width: 100%;

  thead {
    color: rgb(var(--v-theme-neutral-strong));
    font-weight: 600;

    td {
      border-bottom: thin solid rgba(var(--v-border-color), var(--v-border-opacity));
    }

    td:last-of-type {
      padding-left: 30px;
    }
  }

  th, td {
    padding: 10px;
    text-align: left;
  }

  td:last-of-type {
    width: 125px;
  }
}

:deep(.actions-cell .v-icon) {
  color: rgb(var(--v-theme-neutral-strong));
  font-size: 18px;
}
</style>
