<template>
  <div>
    <button-bar
      v-if="editable"
      not-add
      not-discard
      not-update
      not-delete
      not-search
      insert-msg="저장하시겠습니까?"
      @insert="submitData"
    />
    <section class="message">
      <div class="message-body editor">
        <b-field style="display: block;">
          <b-field
            grouped
            group-multiline
            style="flex-wrap: unset;"
          >
            <b-field
              label="구분"
              horizontal
            >
              <b-select
                v-model="type"
                placeholder=""
                size="is-small"
                expanded
                :disabled="!editable"
              >
                <option
                  v-for="option in combo"
                  :key="option.description"
                  :value="option.value"
                >
                  {{ option.description }}
                </option>
              </b-select>
            </b-field>
            <b-field
              label="제목"
              horizontal
            >
              <b-input
                v-model="title"
                expanded
                type="search"
                custom-class="is-small"
                :disabled="!editable"
              />
            </b-field>
          </b-field>
          <b-field
            label="파일첨부"
            horizontal
          >
            <b-upload
              v-model="dropFiles"
              multiple
              drag-drop
              :disabled="!editable"
              @input="fileAdd"
            >
              첨부할 파일을 드래그하십시오
            </b-upload>
          </b-field>

          <div class="tags">
            <span
              v-for="(file, index) in initFiles"
              :key="`i-${index}`"
              class="tag is-primary"
            >
              <a
                class="file-tag"
                @click="downloadFile(file.file, file.type, file.name)"
              >
                {{ file.name }}
              </a>
              <button
                v-if="editable"
                class="delete is-small"
                type="button"
                @click="deleteInitFile(index)"
              />
            </span>
            <span
              v-for="(file, index) in dropFiles"
              :key="index"
              class="tag is-primary"
            >
              {{ file.name }}
              <button
                class="delete is-small"
                type="button"
                @click="deleteDropFile(index)"
              />
            </span>
          </div>
          <b-field style="flex-wrap: unset;">
            <u-editor
              v-model="content"
              :readonly="!editable"
            />
          </b-field>
        </b-field>
      </div>
    </section>
    <b-loading
      :is-full-page="isFullPage"
      :active.sync="isLoading"
      :can-cancel="true"
    >
      <b-icon
        pack="fas"
        icon="sync-alt"
        size="is-large"
        custom-class="fa-spin"
      />
    </b-loading>
  </div>
</template>

<script>

export default {
  props: {
    combo: Array,
    serviceUrl: String,
    selectMethod: String,
    writeMoethod: String,
    uploadMethod: String,
    tableName: String,
    no: Number,
    htmlSize: {
      type: Number,
      default: 60000,
    },
    fileSize: {
      type: Number,
      default: 16,
    },
    fileTotalSize: {
      type: Number,
      default: 40,
    },
    fileCnt: {
      type: Number,
      default: 3,
    },
    permission: String,
  },
  data() {
    return {
      isLoading: false,
      isFullPage: true,
      type: '',
      title: '',
      dropFiles: [],
      initFiles: [],
      content: '',
      deleteFiles: [],
      editable: false,
      totalSize: 0,
    };
  },
  watch: {
    no(newVal) {
      this.selectData(newVal);
    },
  },
  mounted() {
    if (this._props.no > 0) {
      this.editable = this._props.user == this.$user.id;
    } else {
      this.editable = this.$user.hasPermission(this._props.permission);
    }
  },
  methods: {
    selectData(no) {
      if (no > 0) {
        this.isLoading = true;
        this.$service
          .read(this._props.serviceUrl + this._props.selectMethod, { no: Number(no) })
          .then(({ data }) => {
            this.title = data.notice[0].title;
            this.type = data.notice[0].type;
            this.content = unescape(data.notice[0].contents);
            this.initFiles = data.file;
            this.dropFiles = [];
            this.deleteFiles = [];
            this.editable = data.notice[0].user == this.$user.id;
          })
          .catch((error) => {
            this.$buefy.dialog.alert({
              message: '작업에 실패하였습니다.',
              type: 'is-danger',
            });
          })
          .finally(() => {
            this.isLoading = false;
          });
      } else {
        this.editable = this.$user.hasPermission(this._props.permission);
      }
    },
    async submitData() {
      const size = this.getTextLength(escape(this.content));
      if (this.title == null || this.title == '') {
        return;
      }
      if (this.type == null || this.type == '') {
        return;
      }
      if (this.content == null || this.content == '') {
        return;
      }
      if (size > this._props.htmlSize) {
        this.$buefy.dialog.alert({
          message: '용량을 초과하였습니다.',
          type: 'is-danger',
        });
        return;
      }
      const param = {
        no: this._props.no,
        type: this.type,
        title: this.title,
        contents: escape(this.content),
      };

      let fileChange = false;
      if (this.dropFiles.length > 0 || this.deleteFiles.length > 0) {
        fileChange = true;
      }

      let { no } = param;

      try {
        const resultNotice = await this.$service.modify(
          this._props.serviceUrl + this._props.writeMoethod,
          param,
        );
        no = resultNotice.data;
      } catch (error) {
        this.$buefy.dialog.alert({
          message: '글읽기에 실패하였습니다.',
          type: 'is-danger',
        });
      } finally {
        if (fileChange) {
          const formData = new FormData();
          this.dropFiles.forEach((file) => {
            if (file.size < this._props.fileSize * 1024 * 1024) {
              formData.append('files', file);
            }
          });
          formData.append('tb_nm', this._props.tableName);
          formData.append('key', no);
          formData.append('delFiles', this.deleteFiles);
          try {
            const resultFile = await this.fileUpload(formData);
          } catch (error) {
            this.$buefy.dialog.alert({
              message: '파일 업로드에 실패하였습니다.',
              type: 'is-danger',
            });
          } finally {
            this.selectData(no);
          }
        } else {
          this.selectData(no);
        }
      }
    },
    fileAdd() {
      const { length } = this.dropFiles;
      if (length > this._props.fileCnt) {
        this.dropFiles.splice(this._props.fileCnt);
        this.$buefy.dialog.alert({
          message: `파일 최대 업로드 수(${this._props.fileCnt}개) 초과`,
          type: 'is-danger',
        });
        return;
      }
      this.dropFiles.forEach((file, index) => {
        if (file.size > this._props.fileSize * 1024 * 1024) {
          this.$buefy.dialog.alert({
            message: `파일 하나 최대 크기 초과(${this._props.fileSize}MB)`,
            type: 'is-danger',
          });
          this.dropFiles.splice(index, 1);
          this.totalSize += file.size;
        } else if (this.totalSize > this._props.fileTotalSize * 1024 * 1024) {
          this.$buefy.dialog.alert({
            message: `전체 파일 허용 크기 초과(${this._props.fileTotalSize}MB)`,
            type: 'is-danger',
          });
          this.dropFiles.splice(index, 1);
        }
      });
    },
    setFile(target, typ) {
      const str = target.replace(/[[\]]|(\s*)/g, '');
      const arr = str.split(',');
      for (let i = 0; i < arr.length; i++) {
        arr[i] = Number(arr[i]);
      }
      const bytes = new Uint8Array(arr);
      const blob = new Blob([bytes], {
        type: typ,
      });
      const url = URL.createObjectURL(blob);
      return url;
    },
    downloadFile(target, type, name) {
      const url = this.setFile(target, type);
      const downloadLink = document.createElement('a');
      downloadLink.href = url;
      downloadLink.download = name;

      document.body.appendChild(downloadLink);
      downloadLink.click();
      document.body.removeChild(downloadLink);
    },
    deleteInitFile(index) {
      this.deleteFiles.push(this.initFiles[index].no);
      this.initFiles.splice(index, 1);
    },
    deleteDropFile(index) {
      this.dropFiles.splice(index, 1);
    },
    getTextLength(str) {
      let len = 0;
      for (let i = 0; i < str.length; i++) {
        if (escape(str.charAt(i)).length == 6) {
          len++;
        }
        len++;
      }
      return len;
    },
    async fileUpload(formData) {
      return this.$rest.post(this._props.uploadMethod, {
        body: formData,
      });
    },
  },
};
</script>
<style>
.field.is-horizontal .field-label .label {
  width: max-content;
}
.field.is-grouped .field {
  margin-right: 0.75em;
}
.field.is-grouped.is-grouped-multiline:last-child {
  margin-bottom: unset;
}
.message-body.editor {
  padding-bottom: 0.75rem;
}
.message-body.editor > .field > .field > .field-label {
  align-self: center;
}
@media screen and (min-width: 769px), print {
  .field.is-horizontal .field-label {
    margin-right: 1rem;
    flex-grow: unset;
  }
  .field.is-horizontal .field-label.colon .label::after {
    content: " :";
  }
  .field.is-horizontal > .field-body > .field {
    flex-shrink: unset !important;
  }
}
</style>
