<template>
  <div class="alternates">
    <h2 class="rendition-collection-title">
      Custom Renditions
    </h2>
    <ui-fileupload
      v-if="fileInput"
      label="Upload new image"
      name="file"
      accept="image/x-png,image/gif,image/jpeg"
      @change="previewImage"
    />
    <div class="alternates-container">
      <template
        v-for="{ keyName, name, path } in formattedAlternates"
      >
        <alternate
          :key="`${path}-${keyName}`"
          :key-name="keyName"
          :name="name"
          :path="path"
          :parent-path="parentPath"
          :image-uploaded="imageUploaded"
          :formatted-rendition-names="formattedRenditionNames"
          :rendition-names="renditionNames"
          :validate="validate"
          @removeAlternate="removeAlternate"
          @replaceRendition="replaceRendition"
          @saveAlternate="saveAlternate"
          @validationFailed="alertValidationFailed"
        />
      </template>
    </div>
  </div>
</template>
<script>

import { addAlternate, deleteSingle } from 'Api';
import { ALERT_VALIDATION_FAIL, ALTERNATES } from 'Config/constants';
import { hasStatusError } from 'Helpers/api';
import Alternate from './Alternate.vue';

const { UiFileupload } = window.kiln.utils.components,
  ASPECT_RATIO_ERROR_RANGE = 0.01,
  HIDE_ALERT_TIMEOUT = 5000;

export default {
  components: {
    Alternate,
    UiFileupload
  },
  props: {
    alternates: {
      type: Array,
      default: () => []
    },
    parentPath: {
      type: String,
      default: ''
    },
    previews: {
      type: Object,
      default: () => ({})
    }
  },
  data() {
    return {
      fileInput: true,
      imagePreviewUrl: '',
      file: null,
      imageUploaded: false
    };
  },
  computed: {
    /**
     * Formats the alternates
     * @returns {Object[]} formatted list
     */
    formattedAlternates() {
      const displayList = this.alternates.map(name => ({
        name: this.renditionNames[name],
        keyName: name,
        path: ''
      }));

      if (this.imagePreviewUrl) displayList.unshift({ name: '', path: this.imagePreviewUrl });

      return displayList;
    },
    /**
     * Formats the renditions names
     * @returns {Object[]} formatted list
     */
    formattedRenditionNames() {
      return Object.keys(this.renditionNames).map(name => ({
        label: this.renditionNames[name],
        value: name,
        class: this.alternates.includes(name) ? 'disabled' : ''
      }));
    },
    renditionNames() {
      const names = Object.entries(this.previews).reduce((accum, [previewKey, { name = '' }]) => ({
          ...accum,
          [previewKey]: name
        }), {}),
        silo = ALTERNATES.SILO.value;

      return { silo, ...names };
    }
  },
  methods: {
    /**
     * Clears data
     */
    clear() {
      this.imagePreviewUrl = '';
      this.file = null;
      this.clearUpload();
      this.imageUploaded = true;
      this.$emit('resetReplacedRendition');
    },
    /**
     * Clears file upload input
     */
    clearUpload() {
      this.fileInput = false;
      this.$nextTick(() => {
        this.fileInput = true;
      });
    },
    /**
     * Handles delete custom rendition from list
     * @param {string} path Path of custom rendition to delete
     * @param {string} renditionName Name of custom rendition
     */
    removeAlternate(path = '', renditionName = '') {
      if (!renditionName) {
        this.clear();

        return;
      }

      deleteSingle(path)
        .then((data) => {
          if (hasStatusError(data)) {
            this.$emit('alert', `${data.error}: ${data.message}`);
          }
        })
        .then(() => {
          this.$emit('removeAlternate', renditionName);
          this.clear();
        })
        .catch((e) => {
          console.error(e);
        });
    },
    /**
     * Previews image uploaded
     * @param {File} files Array with file uploaded
     */
    previewImage(files) {
      const [file] = files;

      this.file = file;
      this.imagePreviewUrl = URL.createObjectURL(this.file);
      this.clearUpload();
    },
    /**
     * Handles the name selection and saves changes
     * @param {string} newRendition String with name of new rendition
     */
    replaceRendition(newRendition = '') {
      this.$emit('replaceRendition', newRendition);
    },
    /**
     * Handles the name selection and saves changes
     * @param {string} newRendition String with name of new rendition
     */
    saveAlternate(newRendition = '') {
      addAlternate(this.file, this.parentPath, newRendition)
        .then((data) => {
          if (hasStatusError(data)) {
            this.$emit('alert', `${data.error}: ${data.message}`);
          }
        })
        .then(() => {
          this.$emit('saveAlternate', newRendition);
          this.clear();
        })
        .catch((e) => {
          console.error(e);
        });
    },
    /**
     * Validates if new file has expected aspect ratio
     * @param {string} newRendition String with name of new rendition
     * @param {number} imgHeight Height of image uploaded
     * @param {number} imgWidth Width of image uploaded
     * @returns {Boolean}
     */
    validate(newRendition = '', imgHeight = 1, imgWidth = 0) {
      if (this.file && newRendition) {
        // if there is something selected, it means it was taken from the list provided
        const { height = 1, width = 1 } = this.previews[newRendition],
          obtainedRatio = imgWidth / imgHeight,
          expectedRatio = width / height;

        return (obtainedRatio >= expectedRatio - ASPECT_RATIO_ERROR_RANGE)
          && (obtainedRatio <= expectedRatio + ASPECT_RATIO_ERROR_RANGE);
      }

      // either there is no file or new rendition is not correct
      return false;
    },
    /**
     * Alerts that the validation failed to parent
     */
    alertValidationFailed() {
      this.$emit('alert', ALERT_VALIDATION_FAIL, false);
      this.$emit('resetReplacedRendition');

      setTimeout(() => {
        this.$emit('resetAlert', ALERT_VALIDATION_FAIL);
      }, HIDE_ALERT_TIMEOUT);
    }
  }
};
</script>
<style lang="scss" scoped>
  @import 'Styles/colors.scss';
  @import 'Styles/fonts.scss';

  .alternates {
    grid-row: 5;

    .ui-fileupload {
      @extend .title;

      font-weight: bold;
      margin: 10px 0 30px 10px;
    }
  }

  @media screen and (min-width: 2200px) {
    .alternates {
      grid-column: 2;
      grid-row: 3;
      margin-left: 40px;
    }
  }
</style>
