import {ApplicationRef, ChangeDetectorRef, Component, EventEmitter, Input, OnDestroy, OnInit, Output, NgZone, OnChanges} from '@angular/core';
import {NzMessageService, NzNotificationService, UploadFile} from 'ng-zorro-antd';
import {HttpClient, HttpEvent, HttpEventType, HttpRequest} from '@angular/common/http';
import {environment} from '../../../environments/environment';

declare var Recorder;

@Component({
  selector: 'app-audio-recorder',
  templateUrl: './audio-recorder.component.html',
  styleUrls: ['./audio-recorder.component.scss']
})
export class AudioRecorderComponent implements OnInit, OnChanges, OnDestroy {
  _audioUrl: string;
  audio = new Audio();
  playIcon = 'play';
  isPlaying = false;
  isRecording = false;
  isUploading = false;
  type = Type.UPLOAD; // record | upload
  Type = Type;
  @Input()
  withRmBtn = false;

  uploadUrl;
  uploadData;

  @Input()
  needRemove = false;

  @Input()
  audioItem: any = null;

  @Input()
  set audioUrl(url) {
    this._audioUrl = url;
    if (url) {
      this.audio.src = this._audioUrl;
      this.audio.load();
    }
    this.init();
  }

  get audioUrl() {
    return this._audioUrl;
  }

  @Output() audioUploaded = new EventEmitter();
  @Output() audioUploadFailure = new EventEmitter();
  @Output() audioRemoved = new EventEmitter();
  percent = 0;
  progress = 0;
  recorder: any;
  audioBlob: any;


  constructor( private nzMessageService: NzMessageService,
               private zone: NgZone,
               private nzNotificationService: NzNotificationService,
               private appRef: ApplicationRef,
               private changeDetectorRef: ChangeDetectorRef,
               private httpClient: HttpClient) {
    this.uploadUrl = (<any> window).courseware.uploadUrl();
    this.uploadData = (<any> window).courseware.uploadData();

    window['air'].getUploadCallback = (url, data) => {
      this.uploadUrl = url;
      this.uploadData = data;
    };
    this.recorder = new Recorder({
      sampleRate: 44100, // 采样频率,默认为44100Hz(标准MP3采样率)
      bitRate: 128, // 比特率,默认为128kbps(标准MP3质量)
      success: () => { // 成功回调函数
      },
      error: (msg) => { // 失败回调函数
        this.nzNotificationService.error('Init Audio Recorder Failed', msg, {nzDuration: 0});
      },
      fix: (msg) => { // 不支持H5录音回调函数
        this.nzNotificationService.error('Init Audio Recorder Failed', msg, {nzDuration: 0});
      }
    });
  }

  init() {
    this.playIcon = 'play';
    this.isPlaying = false;
    this.isRecording = false;
    this.isUploading = false;
    this.percent = 0;
    this.progress = 0;
    this.audioBlob = null;
  }
  ngOnChanges() {
    // if (!this.audioItem || !this.audioItem.type) {
    //   return;
    // }
    // this.beforeUpload(this.audioItem);
  }
  ngOnInit() {

    this.audio.onplay = () => {
      this.onPlay();
    };
    this.audio.onpause = () => {
      this.onPause();
    };
    this.audio.ontimeupdate = (event) => {
      this.onTimeUpdate(event);
    };
    this.audio.onended = (event) => {
      this.onEnded();
    };
  }

  ngOnDestroy() {
    this.audio.pause();
    this.isPlaying = false;
    this.audio.remove();
    if (this.recorder.worker) {
      this.recorder.worker.terminate();
    }
  }

  progressText(percent) {
    return ``;
  }

  onPlay() {
    console.log('play');
    this.playIcon = 'pause';
    this.isPlaying = true;
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }

  onPause() {
    console.log('pause');
    this.playIcon = 'play';
    this.isPlaying = false;
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();

  }

  onEnded() {
    console.log('on end');
    this.playIcon = 'play';
    this.percent = 0;
    this.isPlaying = false;
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }

  onTimeUpdate(event) {
    this.percent = Math.floor((this.audio.currentTime / this.audio.duration) * 100);
  }

  onBtnPlay() {
    if (this.isRecording) {
      this.nzMessageService.warning('In Recording');
      return;
    }
    if (this.isPlaying) {
      this.audio.pause();
    } else {
      this.audio.play();
    }
  }

  // 开始录音
  onBtnRecord = () => {
    if (!this.isRecording) {
      this.isRecording = true;
      this.recorder.start();
    } else {
      this.isRecording = false;
      this.recorder.stop();
      this.recorder.getBlob((blob) => {
        this.audio.src = URL.createObjectURL(blob);
        this.audioBlob = blob;
        this.isUploading = true;
        const formData = new FormData();
        formData.append('file', blob, 'courseware-item-record.mp3');
        const req = new HttpRequest('POST', this.uploadUrl, formData, {
          reportProgress: true
        });

        this.httpClient.request(req)
          .subscribe((event: HttpEvent<any>) => {
            switch (event.type) {
              case HttpEventType.UploadProgress:
                this.zone.run(() => {
                  this.progress = Math.floor(100 * event.loaded / event.total);
                  this.changeDetectorRef.markForCheck();
                  this.changeDetectorRef.detectChanges();
                  this.refresh();
                });
                break;
              case HttpEventType.Response:
                this.zone.run(() => {
                  console.log(event);
                  this.audioUploaded.emit(event.body);
                  this.isUploading = false;
                  this.changeDetectorRef.markForCheck();
                  this.changeDetectorRef.detectChanges();
                  this.refresh();
                });
                break;
            }
          }, (error) => {
            console.error(error);
            this.isUploading = false;
          });
      });
    }
  }

  // 切换模式
  onBtnSwitchType() {
    if (this.isUploading) {
      this.nzMessageService.warning('In Uploading');
      return;
    } else if (this.isRecording) {
      this.nzMessageService.warning('In Recording');
      return;
    }
    if (this.type === Type.RECORD) {
      this.type = Type.UPLOAD;
    } else {
      this.type = Type.RECORD;
    }
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }
  refresh() {
    setTimeout(() => {
      this.appRef.tick();
    }, 1);
  }
  onBtnClearAudio() {
    this.audioUrl = null;
    this.audioRemoved.emit();
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }

  onBtnDeleteAudio() {
    this.audioUrl = null;
    this.audioRemoved.emit();
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }

  handleChange(info: { type: string, file: UploadFile, event: any }): void {
    switch (info.type) {
      case 'start':
        this.isUploading = true;
        this.progress = 0;
        break;
      case 'success':
        this.isUploading = false;
        this.uploadSuccess(info.file.response);
        this.audioUploaded.emit(info.file.response);
        break;
      case 'progress':
        this.progress = parseInt(info.event.percent, 10);
        break;
    }
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }
  checkSelectFile(file: any) {
    if (!file) {
      return;
    }
    const isAudio = ['audio/mp3', 'audio/wav', 'audio/ogg'].includes(file.type);
    if (!isAudio) {
      this.nzMessageService.error('You can only upload Audio file ( mp3 | wav |ogg)');
      return;
    }
    const delta =  25;
    const isOverSize = (file.size / 1024 / 1024) < delta;
    if (!isOverSize) {
      this.nzMessageService.error(`audio file  must smaller than ${delta}MB!`);
      return false;
    }
    return true;
  }
  beforeUpload = (file: File) => {

    this.audioUrl = null;
    if (!this.checkSelectFile(file)) {
      return false;
    }
    this.isUploading = true;
    this.progress = 0;
  }
  uploadSuccess = (url) => {
    this.nzMessageService.info('Upload Success');
    this.isUploading = false;
    this.audioUrl = url;
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }
  uploadFailure = (err, file) => {
    this.isUploading = false;
    if (err.name && err.name === 'cancel') {
      return;
    }
    console.log(err);
    this.nzMessageService.error('Upload Error ' + err.message);
    this.audioUploadFailure.emit(file);
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }
  doProgress = (p) => {
    if (p > 1) {
      p = 1;
    }
    if (p < 0) {
      p = 0;
    }
    // console.log(Math.floor(p * 100));
    this.progress =  Math.floor(p * 100);
    this.changeDetectorRef.markForCheck();
    this.changeDetectorRef.detectChanges();
    this.refresh();
  }

}

enum Type {
  RECORD = 1, UPLOAD
}