import { Errors } from 'laravel-nova'

export default {
  props: {
    resourceName: String,

    actions: {},

    pivotActions: {
      default: () => [],
    },

    endpoint: {
      type: String,
      default: null,
    },

    queryString: {
      type: Object,
      default: () => ({
        currentSearch: '',
        encodedFilters: '',
        currentTrashed: '',
        viaResource: '',
        viaResourceId: '',
        viaRelationship: '',
      }),
    },
  },

  data: () => ({
    working: false,
    selectedActionKey: '',
    errors: new Errors(),
    confirmActionModalOpened: false,
  }),

  methods: {
    /**
     * Determine whether the action should redirect or open a confirmation modal
     */
    determineActionStrategy() {
      if (this.selectedAction.withoutConfirmation) {
        this.executeAction()
      } else {
        this.openConfirmationModal()
      }
    },

    /**
     * Confirm with the user that they actually want to run the selected action.
     */
    openConfirmationModal() {
      this.confirmActionModalOpened = true
    },

    /**
     * Close the action confirmation modal.
     */
    closeConfirmationModal() {
      this.confirmActionModalOpened = false
      this.errors = new Errors()
    },

    /**
     * Close the action response modal.
     */
    closeActionResponseModal() {
      this.showActionResponseModal = false
    },

    /**
     * Initialize all of the action fields to empty strings.
     */
    initializeActionFields() {
      _(this.allActions).each(action => {
        _(action.fields).each(field => {
          field.fill = () => ''
        })
      })
    },

    /**
     * Execute the selected action.
     */
    executeAction() {
      this.working = true

      Nova.request({
        method: 'post',
        url: this.endpoint || `/nova-api/${this.resourceName}/action`,
        params: this.actionRequestQueryString,
        data: this.actionFormData(),
      })
        .then(response => {
          this.confirmActionModalOpened = false
          this.handleActionResponse(response.data)
          this.working = false
        })
        .catch(error => {
          this.working = false

          if (error.response.status == 422) {
            this.errors = new Errors(error.response.data.errors)
            Nova.error(this.__('There was a problem executing the action.'))
          }
        })
    },

    /**
     * Gather the action FormData for the given action.
     */
    actionFormData() {
      return _.tap(new FormData(), formData => {
        formData.append('resources', this.selectedResources)

        _.each(this.selectedAction.fields, field => {
          field.fill(formData)
        })
      })
    },

    /**
     * Handle the action response. Typically either a message, download or a redirect.
     */
    handleActionResponse(data) {
      if (data.modal) {
        this.actionResponseData = data
        this.showActionResponseModal = true
      } else if (data.message) {
        this.$emit('actionExecuted')
        Nova.$emit('action-executed')
        Nova.success(data.message)
      } else if (data.deleted) {
        this.$emit('actionExecuted')
        Nova.$emit('action-executed')
      } else if (data.danger) {
        this.$emit('actionExecuted')
        Nova.$emit('action-executed')
        Nova.error(data.danger)
      } else if (data.download) {
        let link = document.createElement('a')
        link.href = data.download
        link.download = data.name
        document.body.appendChild(link)
        link.click()
        document.body.removeChild(link)
      } else if (data.redirect) {
        window.location = data.redirect
      } else if (data.push) {
        this.$router.push(data.push)
      } else if (data.openInNewTab) {
        window.open(data.openInNewTab, '_blank')
      } else {
        this.$emit('actionExecuted')
        Nova.$emit('action-executed')
        Nova.success(this.__('The action ran successfully!'))
      }
    },
  },

  computed: {
    /**
     * Get the query string for an action request.
     */
    actionRequestQueryString() {
      return {
        action: this.selectedActionKey,
        pivotAction: this.selectedActionIsPivotAction,
        search: this.queryString.currentSearch,
        filters: this.queryString.encodedFilters,
        trashed: this.queryString.currentTrashed,
        viaResource: this.queryString.viaResource,
        viaResourceId: this.queryString.viaResourceId,
        viaRelationship: this.queryString.viaRelationship,
      }
    },

    /**
     * Get all of the available actions.
     */
    allActions() {
      return this.actions.concat(this.pivotActions.actions)
    },

    /**
     * Return the selected action being executed.
     */
    selectedAction() {
      if (this.selectedActionKey) {
        return _.find(this.allActions, a => a.uriKey == this.selectedActionKey)
      }
    },

    /**
     * Determine if the selected action is a pivot action.
     */
    selectedActionIsPivotAction() {
      return (
        this.hasPivotActions &&
        Boolean(
          _.find(this.pivotActions.actions, a => a === this.selectedAction)
        )
      )
    },

    /**
     * Get all of the available actions for the resource.
     */
    availableActions() {
      return _(this.actions)
        .filter(action => {
          if (this.selectedResources.length == 0) {
            return action.standalone
          }

          return true
        })
        .value()
    },

    /**
     * Get all of the available pivot actions for the resource.
     */
    availablePivotActions() {
      return _(this.pivotActions.actions)
        .filter(action => {
          if (this.selectedResources.length == 0) {
            return action.standalone
          }

          if (this.selectedResources != 'all') {
            return true
          }

          return action.availableForEntireResource
        })
        .value()
    },

    /**
     * Determine whether there are any pivot actions
     */
    hasPivotActions() {
      return this.availablePivotActions.length > 0
    },
  },
}
