import { Component, Prop, Vue, Watch } from 'vue-property-decorator';
import { QFile } from 'quasar';

declare interface BaseUploaderRefs {
  uploader: QFile;
  [key: string]: Vue | Element | Vue[] | Element[];
}

@Component({})
class BaseUploader extends Vue {
  $refs!: BaseUploaderRefs;

  @Prop({
    default: '',
  })
  private accept?: string;

  @Prop({
    default: false,
  })
  private rulesForRejected?: boolean;

  @Prop({
    default: true,
  })
  private description?: boolean | string;

  @Prop({
    default: true,
  })
  private showDescription?: boolean;

  @Prop({
    default: true,
  })
  private showAction?: boolean;

  @Prop({
    default: false,
  })
  private disable?: boolean;

  @Prop({
    default: false,
  })
  private multiple?: boolean;

  @Prop({
    default: true,
  })
  private needFile?: boolean;

  @Prop({
    default: () => [],
  })
  private rules?: ((val?: string) => boolean | string)[];

  @Prop({
    default: '',
  })
  private inputLabel?: string;

  @Prop({
    default: true,
  })
  private withInput?: boolean;

  @Watch('description', {
    immediate: true,
  })
  private descriptionHandler(val: boolean | string): void {
    if (typeof val === 'string') {
      this.model.description.value = val;
    }
  }

  private model: BaseUploaderModel = {
    description: {
      value: '',
    },
    files: [],
    loading: false,
  };

  private isValid = false;

  private get uploader(): QFile {
    return this.$refs.uploader || {};
  }

  private clearHandler(files: File[]): void {
    this.model.files = [];

    this.$emit('clear', files);
  }

  private inputHandler(val: File | File[] | null): void {
    if (val) {
      if (!Array.isArray(val)) {
        this.model.files = [val];
      }
      this.isValid = Boolean(this.uploader.validate([val]));
    } else {
      this.model.files = [];
    }

    this.$emit('input', this.model.files);
  }

  private rejectHandler(val: any[] | FileList): void {
    if (this.rulesForRejected && val) {
      this.uploader.validate([val[0].file]);
    }
  }

  get isNotAvailible(): boolean {
    return (
      this.disable ||
      !!(this.needFile && !(this.model?.files?.length && this.isValid))
    );
  }

  protected get currentInputLabel(): string {
    return this.inputLabel || String(this.$t('base.uploader.description'));
  }

  private doneHandler(): void {
    this.model.loading = false;
  }

  private uploadHandler(): void {
    this.model.loading = true;

    const data: {
      description?: string;
      files: File[];
    } = {
      files: this.model.files,
    };

    if (this.showDescription) {
      data.description = this.model.description.value;
    }

    this.$emit('upload', data, this.doneHandler);
  }
}

interface BaseUploaderModelDescription {
  value: string;
}

interface BaseUploaderModel {
  description: BaseUploaderModelDescription;
  files: File[];
  loading: boolean;
}

export default BaseUploader;
