<template>
  <div
    v-show="!isHidden"
    class="form-group"
    :class="[
      columnSize,
      {
        'has-icon': faIcon,
        'has-feedback': hasFeedback,
        'has-success': hasSuccess,
        'has-error': hasError,
      },
    ]"
  >
    <label class="control-label" :for="id">
      {{ label }}
      <span class="info">{{ info }}</span>
      <span v-if="isRequired" class="required-marker"></span>
      <span
        v-if="tooltip"
        class="tooltip-info"
        data-toggle="tooltip"
        :title="tooltip"
      ></span>
    </label>

    <div class="file-picker">
      <!-- File Details -->
      <div v-if="files.length" class="file-details">
        <div class="active" data-toggle="collapse">
          {{ files.length }} Attachments
        </div>
        <div class="collapse in" style>
          <div
            v-for="(file, fileIndex) in files"
            class="file-label"
            :key="fileIndex"
          >
            {{ file | renderFileItem }}
            <span @click="deleteFile(file.name)" class="close"></span>
          </div>
        </div>
      </div>
      <!-- File Uploader -->
      <div v-if="uploading_progress" class="file-uploader">
        Uploading
        <strong>{{ uploading_file_name }}</strong>
        <span class="upload-status">
          {{
            ((uploading_progress / 100) * uploading_file_size) | humanFileSize
          }}
          of
          {{ uploading_file_size | humanFileSize }}
        </span>
        <div class="progress">
          <div
            class="progress-bar"
            role="progressbar"
            :style="{ width: uploading_progress + '%' }"
          ></div>
        </div>
      </div>
      <!-- File Dropzone -->
      <div
        class="file-dropzone"
        :class="{
          disabled: uploading_progress > 0,
        }"
      >
        <input
          type="file"
          :ref="id"
          :id="id"
          multiple
          @input="onInput"
          @focus="onFocus"
          @blur="onBlur"
          :required="isRequired"
          :disabled="!isEnabled"
        />
        <i class="fa fa-paperclip" aria-hidden="true"></i>
        <span class="hidden-desktop one-line">
          <a>Browse files</a>
        </span>
        <span class="hidden-mobile">
          Choose files to upload
          <br />
          <a>Browse files</a>
        </span>
      </div>
    </div>
    <!-- Preview Panel -->
    <div v-if="previews" class="panel-group">
      <div
        v-for="(preview, previewName, previewIndex) in previews"
        class="panel panel-default"
        :key="previewName"
      >
        <div
          class="panel-heading collapsed"
          data-toggle="collapse"
          :data-target="'#' + id + 'preview' + previewIndex"
        >
          <h4 class="panel-title">Preview {{ preview.fileName }}</h4>
        </div>
        <div
          :id="id + 'preview' + previewIndex"
          class="panel-collapse collapse"
        >
          <div class="panel-body"></div>
        </div>
      </div>
    </div>

    <div
      v-if="validationText && hasError"
      class="help-block"
      data-validation-error
    >
      {{ validationText }}
    </div>
    <p v-if="help && !validationText" :id="id + 'Help'" class="help-block">
      {{ help }}
    </p>
  </div>
</template>

<script>
import { str2bool, humanFileSize } from "../../util";
import axios from "axios";
export default {
  name: "bc-file-picker",
  props: {
    id: {
      type: String,
      default: null,
    },
    label: {
      type: String,
      default: null,
    },
    value: {
      type: String,
      default: null,
    },
    upload_path: {
      type: String,
      default: null,
    },
    help: {
      type: String,
      default: null,
    },
    info: {
      type: String,
      default: null,
    },
    tooltip: {
      type: String,
      default: null,
    },
    validation: {
      type: String,
      default: null,
    },
    column_size: {
      type: Number,
      default: null,
    },
    is_enabled: {
      type: [Boolean, String],
      default: true,
    },
    is_hidden: {
      type: [Boolean, String],
      default: false,
    },
    is_required: {
      type: [Boolean, String],
      default: false,
    },
    is_valid: {
      type: [Boolean, String],
      default: null,
    },
  },
  data() {
    return {
      isOnFocus: false,
      isValid: null,
      inputValue: null,
      files: [],
      previews: {},
      uploading_error_text: "",
      uploading_file_size: "",
      uploading_file_name: "",
      uploading_progress: 0,
    };
  },
  watch: {
    value: {
      immediate: true,
      handler(newValue) {
        this.inputValue = newValue;
      },
    },
  },
  mounted() {
    if (this.value) {
      this.inputValue = this.value;
    }
    this.isValid = str2bool(this.is_valid, null);
  },
  updated() {
    if (this.value) {
      this.inputValue = this.value;
    }
    if (this.uploading_error_text) {
      this.isValid = false;
      this.isOnFocus = false;
    } else {
      this.isValid = str2bool(this.is_valid, null);
    }
  },
  filters: {
    humanFileSize: (size) => {
      if (size) return humanFileSize(size, true);
      return "";
    },
    renderFileItem: (file) => {
      if (file) {
        let size = humanFileSize(file.size, true);
        let last_modified = new Date(file.lastModified).toLocaleString("en-gb");
        let item = `${file.name} (size: ${size}, modified: ${last_modified})`;
        return item;
      }
      return "";
    },
  },
  computed: {
    isRequired() {
      return str2bool(this.is_required);
    },
    isHidden() {
      return str2bool(this.is_hidden, false);
    },
    isEnabled() {
      return str2bool(this.is_enabled, true);
    },
    hasFeedback() {
      if (this.isValid == null) {
        return false;
      } else {
        return !this.isOnFocus;
      }
    },
    hasError() {
      return !this.isOnFocus && this.isValid === false && this.hasFeedback;
    },
    hasSuccess() {
      return !this.isOnFocus && this.isValid === true && this.hasFeedback;
    },
    columnSize() {
      if (this.column_size) {
        return `col-xs-${this.column_size}`;
      }
      return "";
    },
    faIcon() {
      if (this.icon) {
        return `fa-${this.icon}`;
      }
      return false;
    },
    validationText() {
      if (this.validation) {
        if (!this.isOnFocus) {
          return this.validation;
        }
      }
      if (this.uploading_error_text) {
        return this.uploading_error_text;
      }
      return false;
    },
  },
  methods: {
    onInput(event) {
      this.isOnFocus = true;
      let files = event.target.files;
      this.$emit("input", files);
      if (files && files.length > 0) {
        let filesArr = Array.from(files);
        filesArr.forEach((file) => {
          // check if the files already exist
          if (!this.files.map((file) => file.name).indexOf(file.name) !== -1) {
            this.uploadFile(file);
          }
        });
      }
    },
    onFocus() {
      this.isOnFocus = true;
    },
    onBlur() {
      // mute validation error if the value is now filled
      if (!this.isValid && this.value) {
        this.isValid = true;
      }
      this.isOnFocus = false;
    },
    uploadFile(file) {
      let formData = new FormData();
      formData.append("file", file);
      this.uploading_file_name = file.name;
      this.uploading_file_size = file.size;
      this.isOnFocus = false;
      axios
        .post(this.upload_path, formData, {
          headers: {
            "Content-Type": "multipart/form-data",
          },
          onUploadProgress: (progressEvent) => {
            this.uploading_progress = parseInt(
              Math.round((progressEvent.loaded / progressEvent.total) * 100)
            );
          },
        })
        .then((response) => {
          this.files.push(file);
          this.uploading_error_text = "";
          this.$emit("response", response);
        })
        .catch((error) => {
          // console.log(error);
          if (error.response) {
            this.uploading_error_text = error.response.data;
          }
        })
        .finally(() => {
          this.uploading_file_name = "";
          this.uploading_file_size = "";
          this.uploading_progress = 0;
          this.clearValue();
        });
    },
    deleteFile(file) {
      // console.log(`delete file ${file}`);
      this.files = this.files.filter((item) => item.name !== file);
    },
    clearValue() {
      this.$refs[this.id].value = "";
    },
  },
};
</script>

