import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core';
import {RestService} from '../../services/rest.service';
import {NGXLogger} from 'ngx-logger';
import {MatSnackBar} from '@angular/material/snack-bar';
import {ImageMetadata} from '../../interfaces/interface';
// @ts-ignore
import metaFile from '../../../../../iotclient/metadata_full.json';

@Component({
  selector: 'app-file-uploader',
  templateUrl: './file-uploader.component.html',
  styleUrls: ['./file-uploader.component.css']
})
export class FileUploaderComponent implements OnInit {

  constructor(private restService: RestService, private logger: NGXLogger, private snackBar: MatSnackBar) {
  }

  @Input()
  mode: string; // post, put
  @Input()
  filename: string; // if mode==put && without file ending
  @Input()
  meta: ImageMetadata;

  @Output()
  reload: EventEmitter<string> = new EventEmitter<string>();

  currentFileName: string;

  id: string;

  file: ArrayBuffer;
  tag: string;
  longitude: string;
  latitude: string;
  name: string;

  private buildForm(): FormData {
    const mainForm: FormData = new FormData();
    const metaDict: {} = {};

    if (this.filename) {
      this.id = this.filename;
      metaDict['filename'] = this.filename;
    } else {
      this.id = this.currentFileName;
      metaDict['filename'] = this.currentFileName;
    }

    if (this.mode === 'post') {
      if (this.meta && this.meta.longitude && this.meta.latitude) {
        metaDict['longitude'] = this.meta.longitude;
        metaDict['latitude'] = this.meta.latitude;
      } else if (this.longitude && this.latitude) {
        metaDict['longitude'] = Number.parseFloat(this.longitude);
        metaDict['latitude'] = Number.parseFloat(this.latitude);
      } else {
        throw new Error('Long/Lat necessary if new file!');
      }
    }

    if (this.meta && this.meta.name) {
      metaDict['name'] = this.meta.name;
    } else if (this.name) {
      metaDict['name'] = this.name;
    } else {
      if (this.mode === 'post') {
        throw new Error('Name necessary if new file');
      }
    }

    // metaDict['name'] = this.currentFileName;

    if (this.tag) {
      metaDict['tag'] = this.tag;
    } else if (this.meta && this.meta.tag) {
      metaDict['tag'] = this.meta.tag;
    }

    metaDict['datetime'] = new Date().toISOString();

    mainForm.append('id', this.id.split('.')[0]);
    mainForm.append('metadata', JSON.stringify(metaDict));

    if (this.file) {
      let binary = '';
      const bytes = new Uint8Array( this.file );
      const len = bytes.byteLength;
      for (let i = 0; i < len; i++) {
        binary += String.fromCharCode( bytes[ i ] );
      }
      mainForm.append('image_data', window.btoa( binary ));
    } else {
      throw new Error('No file to upload!');
    }

    return mainForm;
  }

  ngOnInit(): void {
    this.logger.debug('meta', metaFile);
  }

  onFileSelected(fileEvent: Event) {
    this.logger.debug('fileEvent', fileEvent);
    const target: HTMLInputElement = fileEvent.target as HTMLInputElement;

    if (typeof (FileReader) !== 'undefined') {
      const reader = new FileReader();
      const file: File = target.files[0];

      reader.onload = (e: any) => {
        this.file = e.target.result;
        this.currentFileName = file.name;
        this.logger.debug('Selected file', this.currentFileName, this.file);
        const metaData = this.loadMetaForFile();
        if (metaData) {
          this.name = metaData.name;
          this.longitude = metaData.longitude + '';
          this.latitude = metaData.latitude + '';
        }
      };

      reader.readAsArrayBuffer(file);
    }
  }

  async postFile() {
    try {
      const formData = this.buildForm();
      this.logger.debug('Build form data', formData);

      let response;
      if (this.mode === 'post') {
        response = await this.restService.postImage(formData).toPromise();
      } else if (this.mode === 'put') {
        response = await this.restService.updateImage(this.id, formData).toPromise();
      } else {
        // noinspection ExceptionCaughtLocallyJS
        throw new Error('Unknown mode: ' + this.mode);
      }

      this.logger.debug('Response', response);

      this.snackBar.open('Upload successful', 'Dismiss');
      this.reload.emit(this.currentFileName);

      this.name = '';
      this.tag = '';
      this.longitude = '';
      this.latitude = '';
    } catch (err) {
      this.logger.error('error', err);
      try {
        this.snackBar.open(err.error.Error, 'Dismiss');
      } catch {
        this.snackBar.open(err.message, 'Dismiss');
      }

    }
  }

  private loadMetaForFile() {
    const metaData = (metaFile as {
      filename: string,
      latitude: number;
      longitude: number;
      name: string;
    }[]).find(m => m.filename === this.currentFileName);
    this.logger.debug('Found corresponding meta', this.currentFileName, metaData);
    return metaData;
  }
}
