import isString from 'lodash/isString';
import { Component, Prop, Ref, Vue, Watch } from 'vue-property-decorator';
import { formatBytes } from '@/recruits/utils';
import { ActivityInfo } from '@components/common/r-file-loader/interfaces';

export interface FileInfo {
  file: File;
  fileName: string;
  fileSize: number;
  fileExt: string;
}

@Component({
  methods: {
    formatBytes,
  },
})
export default class RFileLoader extends Vue {
  @Prop({ default: () => '' })
  readonly supportedFile: string;

  @Prop({ default: () => false })
  readonly multiply: string | boolean;

  @Prop({ default: () => false })
  readonly extentionless: string | boolean;

  @Prop({ default: () => ({}), type: Object })
  readonly activityInfo: ActivityInfo;

  private results: FileInfo[] | null = [];

  @Watch('results')
  emitChange(): void {
    this.$emit('change', this.results);
  }

  @Ref('fileInput') fileInput: HTMLInputElement;

  dragging = false;

  getExtension(result: FileInfo): string {
    return result.fileExt?.slice(1) || '';
  }

  propIsSet(prop: boolean | string): boolean {
    if (isString(prop)) return prop === '';
    return prop;
  }

  handleFileInput(event: DragEvent): void {
    if (!(event.target instanceof HTMLInputElement)) return;
    this.processFileInput(event.target?.files);
    event.target.value = '';
  }

  handleDragOver(event: DragEvent): void {
    event.stopPropagation();
    event.preventDefault();
    this.dragging = event.type === 'dragover';
    if (event.dataTransfer) event.dataTransfer.dropEffect = 'copy';
  }

  handleFileSelect(event: DragEvent): void {
    event.stopPropagation();
    event.preventDefault();
    this.dragging = false;
    this.processFileInput(event.dataTransfer?.files || null);
  }

  getExtention(file: File): string {
    const [ext] = file.name.match(/\.[a-z0-9]+$/i) || [];
    return ext || '';
  }

  matchSupportedFile(ext: string): boolean {
    if (this.propIsSet(this.extentionless)) {
      return ext === '';
    }
    return this.supportedFile
      .split(',')
      .map((ext) => ext.trim())
      .includes(ext);
  }

  readFile(file: any, ext: string): Promise<string | ArrayBuffer | null> {
    return new Promise((resolve, reject) => {
      if (!this.matchSupportedFile(ext)) {
        throw new Error('File extension is not supported');
      }
      const reader = new FileReader();
      reader.onload = () => {
        resolve(reader.result);
      };
      reader.onerror = reject;
      reader.readAsDataURL(file);
    });
  }

  processFileInput(files: FileList | null): void {
    if (!files) return;
    const count = this.propIsSet(this.multiply) ? files.length : 1;
    for (let i = 0; i < count; i++) {
      const file = files[i];
      const ext = this.getExtention(file);

      this.readFile(file, ext).then(() => {
        if (this.results === null) this.results = [];
        const result = {
          fileName: file.name,
          fileSize: file.size,
          file,
          fileExt: ext, // depricated
          ext,
        };
        if (!this.propIsSet(this.multiply)) {
          this.results.splice(-1);
        }
        this.results.push(result);

        if (this.activityInfo.select?.buttonCode)
          this.$recordActivity({
            ...this.activityInfo.select,
            extraInfo: {
              ...this.activityInfo.select.extraInfo,
              file: this.results,
              type: 'file',
            },
          });
      });
      // .finally(() => {
      //   this.$emit('change', this.results);
      // });
    }
  }

  deleteFile(index: number): void {
    if (this.activityInfo.delete?.buttonCode)
      this.$recordActivity({
        ...this.activityInfo.delete,
        extraInfo: {
          ...this.activityInfo.delete.extraInfo,
          file: this.results,
          type: 'file',
        },
      });
    this.results?.splice(index, 1);
    this.$emit('change', this.results);
  }

  clearResults(): void {
    this.results = [];
  }

  clickInput(): void {
    this.fileInput.click();
  }
}
