<template>
  <div v-if="submittedMutation">
    <div class="ui positive message">
      <h4 class="header">
        <translate translate-context="Content/Library/Paragraph">
          Your edit was successfully submitted.
        </translate>
      </h4>
    </div>
    <edit-card
      :obj="submittedMutation"
      :current-state="currentState"
    />
    <button
      class="ui button"
      @click.prevent="submittedMutation = null"
    >
      <translate translate-context="Content/Library/Button.Label">
        Submit another edit
      </translate>
    </button>
  </div>
  <div v-else>
    <edit-list
      :filters="editListFilters"
      :url="mutationsUrl"
      :obj="object"
      :current-state="currentState"
    >
      <div>
        <template v-if="showPendingReview">
          <translate translate-context="Content/Library/Paragraph">
            Recent edits awaiting review
          </translate>
          <button
            class="ui tiny basic right floated button"
            @click.prevent="showPendingReview = false"
          >
            <translate translate-context="Content/Library/Button.Label">
              Show all edits
            </translate>
          </button>
        </template>
        <template v-else>
          <translate translate-context="Content/Library/Paragraph">
            Recent edits
          </translate>
          <button
            class="ui tiny basic right floated button"
            @click.prevent="showPendingReview = true"
          >
            <translate translate-context="Content/Library/Button.Label">
              Restrict to unreviewed edits
            </translate>
          </button>
        </template>
      </div>
      <template #empty-state>
        <empty-state>
          <translate translate-context="Content/Library/Paragraph">
            Suggest a change using the form below.
          </translate>
        </empty-state>
      </template>
    </edit-list>
    <form
      class="ui form"
      @submit.prevent="submit()"
    >
      <div class="ui hidden divider" />
      <div
        v-if="errors.length > 0"
        role="alert"
        class="ui negative message"
      >
        <h4 class="header">
          <translate translate-context="Content/Library/Error message.Title">
            Error while submitting edit
          </translate>
        </h4>
        <ul class="list">
          <li
            v-for="(error, key) in errors"
            :key="key"
          >
            {{ error }}
          </li>
        </ul>
      </div>
      <div
        v-if="!canEdit"
        class="ui message"
      >
        <translate translate-context="Content/Library/Paragraph">
          You don't have the permission to edit this object, but you can suggest changes. Once submitted, suggestions will be reviewed before approval.
        </translate>
      </div>
      <template v-if="values">
        <div
          v-for="fieldConfig in config.fields"
          :key="fieldConfig.id"
          class="ui field"
        >
          <template v-if="fieldConfig.type === 'text'">
            <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
            <input
              :id="fieldConfig.id"
              v-model="values[fieldConfig.id]"
              :type="fieldConfig.inputType || 'text'"
              :required="fieldConfig.required || null"
              :name="fieldConfig.id"
            >
          </template>
          <template v-else-if="fieldConfig.type === 'license'">
            <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>

            <select
              :id="fieldConfig.id"
              ref="license"
              v-model="values[fieldConfig.id]"
              :required="fieldConfig.required || null"
              class="ui fluid search dropdown"
            >
              <option :value="null">
                <translate translate-context="*/*/*">
                  N/A
                </translate>
              </option>
              <option
                v-for="license in licenses"
                :key="license.code"
                :value="license.code"
              >
                {{ license.name }}
              </option>
            </select>
            <button
              class="ui tiny basic left floated button"
              form="noop"
              @click.prevent="values[fieldConfig.id] = null"
            >
              <i class="x icon" />
              <translate translate-context="Content/Library/Button.Label">
                Clear
              </translate>
            </button>
          </template>
          <template v-else-if="fieldConfig.type === 'content'">
            <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
            <content-form
              v-model="values[fieldConfig.id].text"
              :field-id="fieldConfig.id"
              :rows="3"
            />
          </template>
          <template v-else-if="fieldConfig.type === 'attachment'">
            <attachment-input
              :id="fieldConfig.id"
              v-model="values[fieldConfig.id]"
              :initial-value="initialValues[fieldConfig.id]"
              :required="fieldConfig.required || null"
              :name="fieldConfig.id"
              @delete="values[fieldConfig.id] = initialValues[fieldConfig.id]"
            >
              <span>{{ fieldConfig.label }}</span>
            </attachment-input>
          </template>
          <template v-else-if="fieldConfig.type === 'tags'">
            <label :for="fieldConfig.id">{{ fieldConfig.label }}</label>
            <tags-selector
              :id="fieldConfig.id"
              ref="tags"
              v-model="values[fieldConfig.id]"
              required="fieldConfig.required"
            />
            <button
              class="ui tiny basic left floated button"
              form="noop"
              @click.prevent="values[fieldConfig.id] = []"
            >
              <i class="x icon" />
              <translate translate-context="Content/Library/Button.Label">
                Clear
              </translate>
            </button>
          </template>
          <div v-if="fieldValuesChanged(fieldConfig.id)">
            <button
              class="ui tiny basic right floated reset button"
              form="noop"
              @click.prevent="resetField(fieldConfig.id)"
            >
              <i class="undo icon" />
              <translate translate-context="Content/Library/Button.Label">
                Reset to initial value
              </translate>
            </button>
          </div>
        </div>
      </template>
      <div class="field">
        <label for="summary"><translate translate-context="*/*/*">Summary (optional)</translate></label>
        <textarea
          id="change-summary"
          v-model="summary"
          name="change-summary"
          rows="3"
          :placeholder="labels.summaryPlaceholder"
        />
      </div>
      <router-link
        v-if="objectType === 'track'"
        class="ui left floated button"
        :to="{name: 'library.tracks.detail', params: {id: object.id }}"
      >
        <translate translate-context="*/*/Button.Label/Verb">
          Cancel
        </translate>
      </router-link>
      <button
        :class="['ui', {'loading': isLoading}, 'right', 'floated', 'success', 'button']"
        type="submit"
        :disabled="isLoading || !mutationPayload || null"
      >
        <translate
          v-if="canEdit"
          translate-context="Content/Library/Button.Label/Verb"
        >
          Submit and apply edit
        </translate>
        <translate
          v-else
          translate-context="Content/Library/Button.Label/Verb"
        >
          Submit suggestion
        </translate>
      </button>
    </form>
  </div>
</template>

<script>
import $ from 'jquery'
import { isEqual, clone } from 'lodash-es'
import axios from 'axios'
import AttachmentInput from '~/components/common/AttachmentInput.vue'
import EditList from '~/components/library/EditList.vue'
import EditCard from '~/components/library/EditCard.vue'
import TagsSelector from '~/components/library/TagsSelector.vue'
import useEditConfigs from '~/composables/moderation/useEditConfigs'
import { computed } from 'vue'

export default {
  components: {
    EditList,
    EditCard,
    TagsSelector,
    AttachmentInput
  },
  props: {
    objectType: { type: String, required: true },
    object: { type: Object, required: true },
    licenses: { type: Array, required: true }
  },
  setup (props) {
    const configs = useEditConfigs()
    const config = computed(() => configs[props.objectType])
    const currentState = computed(() => config.value.fields.reduce((state/*: Record<string, unknown> */, field) => {
      state[field.id] = { value: field.getValue(props.object) }
      return state
    }, {}))

    return { config, currentState, configs }
  },
  data () {
    return {
      isLoading: false,
      errors: [],
      values: {},
      initialValues: {},
      summary: '',
      submittedMutation: null,
      showPendingReview: true
    }
  },
  computed: {
    canEdit () {
      if (!this.$store.state.auth.authenticated) return false

      const isOwner = this.object.attributed_to &&
        // TODO (wvffle): Is it better to compare ids? Is full_username unique?
        this.$store.state.auth.fullUsername === this.object.attributed_to.full_username

      return isOwner || this.$store.state.auth.availablePermissions.library
    },
    labels () {
      return {
        summaryPlaceholder: this.$pgettext('*/*/Placeholder', 'A short summary describing your changes.')
      }
    },
    mutationsUrl () {
      if (this.objectType === 'track') {
        return `tracks/${this.object.id}/mutations/`
      }
      if (this.objectType === 'album') {
        return `albums/${this.object.id}/mutations/`
      }
      if (this.objectType === 'artist') {
        return `artists/${this.object.id}/mutations/`
      }
      return null
    },
    mutationPayload () {
      const self = this
      const changedFields = this.config.fields.filter(f => {
        return !isEqual(self.values[f.id], self.initialValues[f.id])
      })
      if (changedFields.length === 0) {
        return null
      }
      const payload = {
        type: 'update',
        payload: {},
        summary: this.summary
      }
      changedFields.forEach((f) => {
        payload.payload[f.id] = self.values[f.id]
      })
      return payload
    },
    editListFilters () {
      if (this.showPendingReview) {
        return { is_approved: 'null' }
      } else {
        return {}
      }
    }
  },
  watch: {
    'values.license' (newValue) {
      if (newValue === null) {
        $(this.$refs.license).dropdown('clear')
      } else {
        $(this.$refs.license).dropdown('set selected', newValue)
      }
    }
  },
  created () {
    this.setValues()
  },
  mounted () {
    $('.ui.dropdown').dropdown({ fullTextSearch: true })
  },

  methods: {
    setValues () {
      for (const { id, getValue } of this.config.fields) {
        this.values[id] = clone(getValue(this.object))
        this.initialValues[id] = clone(this.values[id])
      }
    },
    submit () {
      const self = this
      self.isLoading = true
      self.errors = []
      const payload = clone(this.mutationPayload || {})
      if (this.canEdit) {
        payload.is_approved = true
      }
      return axios.post(this.mutationsUrl, payload).then(
        response => {
          self.isLoading = false
          self.submittedMutation = response.data
        },
        error => {
          self.errors = error.backendErrors
          self.isLoading = false
        }
      )
    },
    fieldValuesChanged (fieldId) {
      return !isEqual(this.values[fieldId], this.initialValues[fieldId])
    },
    resetField (fieldId) {
      this.values[fieldId] = clone(this.initialValues[fieldId])
    }
  }

}
</script>
