<template>
  <Modal
    ref="modal"
    :full-height="!!optionalRightSideBar"
    :right-sidebar="!!optionalRightSideBar"
    :content-scrollable="!!optionalRightSideBar"
    :right-sidebar-scrollable="false"
    @hidden="$emit('hidden', { row })"
  >
    <template #content>
      <h2 v-if="primary !== undefined" class="box__title">
        {{ getHeading(primary, row) }}
      </h2>
      <RowEditModalField
        v-for="field in getFields(fields, primary)"
        :key="'row-edit-field-' + field.id"
        :ref="'field-' + field.id"
        :field="field"
        :read-only="readOnly"
        :row="row"
        :table="table"
        @update="update"
        @field-updated="$emit('field-updated', $event)"
        @field-deleted="$emit('field-deleted')"
      ></RowEditModalField>
      <div v-if="!readOnly" class="actions">
        <a
          ref="createFieldContextLink"
          @click="$refs.createFieldContext.toggle($refs.createFieldContextLink)"
        >
          <i class="fas fa-plus"></i>
          {{ $t('rowEditModal.addField') }}
        </a>
        <CreateFieldContext
          ref="createFieldContext"
          :table="table"
          @refresh="$emit('refresh', $event)"
        ></CreateFieldContext>
      </div>
    </template>
    <template v-if="!!optionalRightSideBar" #sidebar>
      <component
        :is="optionalRightSideBar"
        :row="row"
        :read-only="readOnly"
        :table="table"
      ></component>
    </template>
  </Modal>
</template>

<script>
import modal from '@baserow/modules/core/mixins/modal'
import RowEditModalField from '@baserow/modules/database/components/row/RowEditModalField'
import CreateFieldContext from '@baserow/modules/database/components/field/CreateFieldContext'

export default {
  name: 'RowEditModal',
  components: {
    RowEditModalField,
    CreateFieldContext,
  },
  mixins: [modal],
  props: {
    table: {
      type: Object,
      required: true,
    },
    primary: {
      type: Object,
      required: false,
      default: undefined,
    },
    fields: {
      type: Array,
      required: true,
    },
    rows: {
      type: Array,
      required: true,
    },
    readOnly: {
      type: Boolean,
      required: true,
    },
  },
  data() {
    return {
      rowId: -1,
      optionalRightSideBar: this.$registry
        .get('application', 'database')
        .getRowEditModalRightSidebarComponent(),
    }
  },
  computed: {
    /**
     * We need an array containing all available rows because then we can always find
     * the most up to the date row based on the provided id. We need to do it this way
     * because it is possible that the rows are refreshed after for example a field
     * update and we always need the most up to date row. This way eventually prevents
     * incompatible row values.
     *
     * Small side effect is that if the user is editing a row via the modal and another
     * user changes the filters of the same view, then the rows are refreshed for both
     * users. If the current row is then not in the buffer anymore then the modal does
     * not have a data source anymore and is forced to close. This is, in my opinion,
     * less bad compared to old/incompatible data after the user changes the field
     * type.
     */
    row() {
      const row = this.rows.find((row) => row.id === this.rowId)
      if (row === undefined) {
        // If the row is not found in the provided rows then we don't have a row data
        // source anymore which means we can close the modal.
        if (
          this.$refs &&
          Object.prototype.hasOwnProperty.call(this.$refs, 'modal') &&
          this.$refs.modal.open
        ) {
          this.$nextTick(() => {
            this.hide()
          })
        }
        return {}
      }
      return row
    },
  },
  methods: {
    show(rowId, ...args) {
      this.rowId = rowId
      this.getRootModal().show(...args)
    },
    hide(...args) {
      this.getRootModal().hide(...args)
    },
    /**
     * Because the modal can't update values by himself, an event will be called to
     * notify the parent component to actually update the value.
     */
    update(context) {
      context.table = this.table
      this.$emit('update', context)
    },
    getFields(fields, primary) {
      return (primary !== undefined ? [primary].concat(fields) : fields)
        .slice()
        .sort((a, b) => a.order - b.order)
    },
    getHeading(primary, row) {
      const name = `field_${primary.id}`
      if (Object.prototype.hasOwnProperty.call(row, name)) {
        return this.$registry
          .get('field', primary.type)
          .toHumanReadableString(primary, row[name])
      } else {
        return null
      }
    },
  },
}
</script>

<i18n>
{
  "en": {
    "rowEditModal": {
      "addField": "add field"
    }
  },
  "fr": {
    "rowEditModal": {
      "addField": "Ajouter une colonne"
    }
  }
}
</i18n>