import {
  ChangeDetectionStrategy,
  ChangeDetectorRef,
  Component,
  ElementRef,
  EventEmitter,
  Input,
  Output,
  ViewChild,
} from '@angular/core';
import { randomIdGenerator } from '@digi/core/dist/collection/global/utils/randomIdGenerator';
import { UiIconType } from '@ui/icon/icon-type.enum';
/**
 * This component is used for uploading files. It restyles an input type file and emits events when a file is added or
 * removed. It is up to the implementor to actually save the file to a backend.
 */

@Component({
  selector: 'ui-file-upload',
  templateUrl: './file-upload.component.html',
  styleUrls: ['./file-upload.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
})
export class FileUploadComponent {
  iconType = UiIconType;
  /**
   * Label for button
   */
  @Input() uiUploadBtnText = 'Välj filer';
  /**
   * If multiple file upload
   */
  @Input() uiMultiple = false;
  /**
   * UiHeader is used to set the header to the component
   */
  @Input() uiLabel?: string;
  /**
   * If invalid
   */
  @Input() uiInvalid = false;
  /**
   * UiText is used to set the information text
   */
  @Input() uiLabelDescription?: string;
  /**
   * ID for the input
   */
  @Input() uiId: string = randomIdGenerator('ui-fileupload');
  /**
   * uiSecondary is to set outlined or contained variant on the button.
   * Defaults to true.
   */
  @Input() uiSecondary = false;
  /**
   * Maps directly to the input field's accept attribute. Use this to limit accepted file types.
   */
  @Input() uiAccept?: string;
  /**
   * Maps directly to the input field's name attribute.
   */
  @Input() uiName?: string;
  /**
   * Is this a required form field?
   */
  @Input() uiRequired = false;
  /**
   * Max file size allowed in kb
   */
  @Input() uiMaxFileSize: number;
  /**
   * Normally a required field is visually and semantically emphasized.
   * This flips that and emphasizes the field if it is not required.
   * Set this to true if your form contains more required fields than not.
   */
  @Input() uiAnnounceIfOptional = false;
  /**
   * Invalid message
   */
  @Input() uiInvalidMessage?: string;
  /**
   * UiOnUploadFiles is a function which emits all selected files.
   */
  @Output() uiOnUploadFiles: EventEmitter<File[]> = new EventEmitter<File[]>();
  /**
   * UiOnRemoveFile emits when the selected file is successfully removed.
   * Emits the updated array with files.
   */
  @Output() uiOnRemoveFile: EventEmitter<File> = new EventEmitter<File>();
  /**
   * @ignore
   */
  @ViewChild('fileInput') fileInput: HTMLInputElement;
  /**
   * @ignore
   */
  @ViewChild('statusMessage') statusMessage: ElementRef;
  /**
   * @ignore
   */
  files: File[] = [];

  constructor(private changeDetector: ChangeDetectorRef) {}

  /**
   * @ignore
   */
  onUploadFileHandler(event: any): void {
    if (!event.target.files) {
      return;
    }

    if (this.uiMaxFileSize) {
      if (this.convertBytesToKb(2, event.target.files[0].size) > this.uiMaxFileSize) {
        this.uiInvalid = true;
        this.uiInvalidMessage = `
          Filen överskrider max tillåten storlek på
          ${this.convertKbToMb(this.uiMaxFileSize)} MB
        `;
        return;
      } else {
        this.uiInvalid = false;
        this.uiInvalidMessage = '';
      }
    }

    this.files = [...this.files, ...event.target.files];
    this.files.forEach(file => (file['id'] = randomIdGenerator('file')));
    this.uiOnUploadFiles.emit(this.files);

    const fileName = event.target.files[0] ? event.target.files[0].name : '';
    this.updateStatusMessage('add', fileName);
  }

  convertBytesToKb(decimals: number, fileSize: number): number {
    const k = 1024;
    const dm = decimals < 0 ? 0 : decimals;
    const i = Math.floor(Math.log(fileSize) / Math.log(k));
    return parseFloat((fileSize / Math.pow(k, i)).toFixed(dm));
  }

  convertKbToMb(size: number): string {
    return (size / 1024).toFixed(2);
  }

  /**
   * @ignore
   */
  onRemoveFileHandler(id: string) {
    const index = this.files.findIndex(file => file['id'] === id);
    if (index === -1) {
      return;
    }
    const fileToRemove = this.files[index];
    this.files = [...this.files.slice(0, index), ...this.files.slice(index + 1)];
    this.uiOnRemoveFile.emit(fileToRemove);
    this.changeDetector.detectChanges();

    this.updateStatusMessage('remove');
  }

  /**
   * @ignore
   */
  updateStatusMessage(type: string, fileName: string = '') {
    const statusMessage = this.statusMessage.nativeElement;
    statusMessage.textContent = '';

    setTimeout(() => {
      switch (type) {
        case 'remove':
          statusMessage.textContent =
            this.files.length > 0 ? 'Fil borttagen' : 'Fil borttagen. Du har inga filer uppladdade';
          break;
        case 'add':
          statusMessage.textContent = `Fil uppladdad ${fileName}`;
          break;
        default:
          statusMessage.textContent = '';
      }
    }, 50);
  }

  /**
   * @ignore
   */
  get uploadBtnAriaLabel() {
    return this.files.length > 0 && this.uiMultiple ? 'Välj ny fil' : 'Välj fil';
  }
}
