<template>
  <div class="root">
    <div
      ref="pyxis-modal"
      class="list-container"
    >
      <List
        :tags="tags"
        :assets="assets"
        :initial-value="value"
        :items-per-page="itemsPerPage"
        :initial-search="search"
        :initial-filters="initialFilters"
        :last-upload="lastUpload"
        picker-mode
        :reset-filters-flag="removeSelected"
        :selected="selected"
        :site-filter="siteFilter"
        :thumbnail-rendition="thumbnailRendition"
        :total="total"
        :users="users"
        @itemClick="handleItemClick"
        @itemSelect="handleItemClick"
        @scrollToTop="scrollToTop"
        @setAssets="setAssets"
        @setLastUpload="setLastUpload"
        @setTotal="setTotal"
      />
    </div>
    <div
      v-if="multiple"
      class="button-container"
    >
      <ui-button @click="close">
        Cancel
      </ui-button>
      <ui-button
        color="primary"
        :disabled="!selectedLength"
        @click="addImages"
      >
        {{ insertCTA }}
      </ui-button>
    </div>
  </div>
</template>
<script>

import { ITEMS_PER_PAGE_OPTIONS, SITES_NAME_MAPPING } from 'Config';
import { DEFAULT_THUMBNAIL_RENDITION } from 'Config/constants';
import _get from 'lodash/get';
import _cloneDeep from 'lodash/cloneDeep';
import _set from 'lodash/set';
import _tail from 'lodash/tail';
import { fetchUsers, fetchAllConfig, fetchSingle } from 'Api';
import { handleUsersRequest, hasStatusError } from 'Helpers/api';
import { getCropUrl, getIdFromPath, getThumbnailRendition } from 'Helpers/asset';
import List from 'Components/list/List.vue';

export default {
  components: {
    List,
    UiButton: window.kiln.utils.components.UiButton
  },
  props: {
    data: {
      type: Object,
      default: () => ({})
    },
    pluginIntegration: {
      type: Boolean,
      default: false
    },
    removeSelected: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      multiple: this.data.multiple || false,
      search: this.data.search || '',
      filters: this.data.filters || {},
      value: this.data.value || '',
      lastUpload: false,
      selected: {},
      tags: {},
      total: 0,
      assets: [],
      users: [],
      assetTypes: [],
      thumbnailRendition: DEFAULT_THUMBNAIL_RENDITION,
      siteFilter: '',
      dataFromFilters: {}
    };
  },
  computed: {
    initialFilters() {
      return {
        ...this.filters,
        ...this.dataFromFilters
      };
    },
    itemsPerPage() {
      return ITEMS_PER_PAGE_OPTIONS[0];
    },
    insertCTA() {
      return `Insert ${this.selectedLength} image${
        this.selectedLength === 1 ? '' : 's'
      }`;
    },
    selectedLength() {
      return Object.keys(this.selected).length;
    },
    allTagsValues() {
      return Object.values(this.tags)
        .reduce((accum, { values }) => [...values, ...accum], []);
    }
  },
  watch: {
    removeSelected(removeSelectedFlag) {
      if (removeSelectedFlag) {
        this.clearSelected();
      }
    }
  },
  mounted() {
    fetchUsers()
      .then((data) => {
        this.users = handleUsersRequest(data);
      });

    fetchAllConfig()
      .then((config) => {
        const { tags = {}, previews = {} } = config,
          siteName = _get(this.$store, 'state.site.name'),
          mappedSiteName = SITES_NAME_MAPPING[siteName] || siteName;

        this.tags = tags;
        this.thumbnailRendition = getThumbnailRendition(previews);
        this.loadDataFilters();

        if (mappedSiteName && this.allTagsValues.includes(mappedSiteName)) {
          this.siteFilter = mappedSiteName;
        }
      })
      .catch(console.error);
  },
  methods: {
    loadDataFilters() {
      if (this.value) {
        fetchSingle(getIdFromPath(this.value))
          .then((data) => {
            if (hasStatusError(data)) {
              const {
                error = 'Unexpected Error',
                message = 'Error fetching single asset'
              } = data;

              console.error(`${error}: ${message}`);
              return;
            }

            if (data && data.asset && data.asset.metadata) {
              const { collectionSlug, tags } = data.asset.metadata,
                { sites = {} } = this.tags;

              let sitesTags = [];

              if (sites.values && sites.values.length) {
                sitesTags = (tags || []).filter(tag => sites.values.includes(tag));
              }

              this.dataFromFilters = {
                collectionSlug,
                tags: sitesTags
              };
            }
          });
      }
    },
    /**
     * Scrolls the modal to the top
     * @param {number} offset
     */
    scrollToTop(offset = 0) {
      this.$nextTick(() => {
        this.$refs['pyxis-modal'].scrollTop = offset;
      });
    },
    /**
     * Clear selected
     */
    clearSelected() {
      this.selected = {};
    },
    close() {
      this.clearSelected();

      this.pluginIntegration
        ? this.$emit('closeModal')
        : this.$store.dispatch('closeModal');
    },
    /**
     * Handle click on item within List
     * @param {Asset} asset
     */
    handleItemClick(asset) {
      const {
          id,
          referenceName,
          asset: { path }
        } = asset,
        // add referenceName to path
        fullPath = getCropUrl(path, { referenceName });

      this.toggleSelected(id, fullPath);

      if (!this.multiple) {
        this.addImages();
      }
    },
    /**
     * Set last upload value
     * @param {Boolean} value Whether or not last upload is set
     */
    setLastUpload(value) {
      this.lastUpload = value;
    },
    /**
     * toggle item within selected
     * @param {string} id
     * @param {string} path
     */
    toggleSelected(id, path) {
      const temp = Object.assign({}, this.selected);

      if (temp[id]) {
        delete temp[id];
      } else {
        temp[id] = path;
      }
      this.selected = temp;
    },
    /**
     * Set the image on the current component and then create new components with
     * additional selected images
     * Copied and pasted from previous implementation. There's room for improvement here.
     * @return {Promise}
     */
    addImages() {
      const { uri = '', path = '' } = this.data,
        rootPath = path.split('.')[0],
        selectedValues = Object.values(this.selected),
        firstImageURL = selectedValues[0];

      let saveComponentPromise = Promise.resolve();

      if (this.pluginIntegration) {
        this.$emit('selectedImage', firstImageURL);
        this.close();

        return;
      }

      if (this.selectedLength > 0) {
        const currentField = _get(this.$store, `state.components['${uri}']['${rootPath}']`),
          data = {
            [rootPath]: _cloneDeep(currentField)
          };

        _set(data, path, firstImageURL); // support deep paths

        // replace current image with the selected one
        saveComponentPromise = this.$store.dispatch('saveComponent', {
          uri,
          data
        });
      }

      if (this.selectedLength > 1) {
        // create new images (after we've replaced the current image)
        return saveComponentPromise.then(() => {
          const { getParentComponent } = window.kiln.utils.componentElements,
            { refAttr, editAttr, getComponentName } = window.kiln.utils.references,
            componentEl = document.querySelector(`[${refAttr}="${uri}"]`),
            parentEl = getParentComponent(componentEl),
            parentURI = parentEl.getAttribute(refAttr),
            parentPath = componentEl.parentNode.getAttribute(editAttr),
            name = getComponentName(uri);

          return this.$store.dispatch('addComponents', {
            uri,
            parentURI,
            path: parentPath,
            replace: false,
            components: _tail(selectedValues).map((imageURL) => {
              const componentData = {}, // note: there's no current data for new components
                // if it's a complex list, make sure it's added to the first item
                newPath = path.replace(/\.d+\./g, '.0.');

              _set(componentData, newPath, imageURL);

              return {
                name,
                data: componentData
              };
            })
          });
        }).then(() => this.close());
      }

      return saveComponentPromise.then(() => this.close());
    },
    /**
     * Sets total
     * @param {int} value New total value
     */
    setTotal(value) {
      this.total = value;
    },
    /**
     * Handle set assets to state
     * @param {Array} value Array to use as assets value
     */
    setAssets(value) {
      this.assets = value;
    }
  }
};
</script>
<style lang="scss" scoped>
  .list-container {
    overflow-y: auto;
    max-height: 75vh;
  }
  .button-container {
    display: flex;
    padding: 1em 0.5em 0;
    justify-content: space-between;
  }
</style>
