import { observable, action, makeObservable, computed } from "mobx";
import { audioLog } from "./AudioLog";

export class Recorder {
  onRecordingComplete: (data: Blob) => void;
  chunks: Blob[];
  mediaRecorder: MediaRecorder | undefined;
  // observables
  recording: boolean;
  stream: MediaStream | undefined;

  constructor(onRecordingComplete: (data: Blob) => void) {
    this.onRecordingComplete = onRecordingComplete;
    this.recording = false;
    this.mediaRecorder = undefined;
    this.chunks = [];

    makeObservable(this, {
      isRecording: computed,
      recording: observable,
      stop: action,
      start: action,
      init: action,
    });
  }
  get isRecording() {
    return this.recording;
  }

  init = (stream: MediaStream | undefined) => {
    console.log(
      MediaRecorder.isTypeSupported("audio/wav;codecs=MS_PCM"),
    );
    audioLog.logRecorder("Initializing recorder with stream", stream);
    if (stream) {
      this.mediaRecorder = new MediaRecorder(stream, {
        mimeType: "audio/webm;codecs=pcm",
      });
      this.mediaRecorder.ondataavailable = this.onDataAvailable;
      this.mediaRecorder.onstop = this.onStop;
    } else {
      this.mediaRecorder = undefined;
      console.warn("No media stream when initializing the recorder");
    }
  };

  /**
   *
   * @param timeslice The number of milliseconds to record into each Blob. If this
   *  parameter isn't included, the entire media duration is recorded into a single
   *  Blob unless the requestData() method is called to obtain the Blob and trigger
   *  the creation of a new Blob into which the media continues to be recorded.
   */
  start = (timeslice?: number) => {
    this.chunks = [];
    if (this.mediaRecorder) {
      this.mediaRecorder.start(timeslice);
      this.recording = true;
      audioLog.recordingStart();
    }
  };

  stop = () => {
    if (!this.recording) {
      return;
    }
    if (this.mediaRecorder) {
      this.mediaRecorder.stop();
      this.recording = false;
      audioLog.recordingStop();
    }
  };

  onDataAvailable = (event: BlobEvent) => {
    this.chunks.push(event.data);
  };

  onStop = () => {
    // prepare audio for playback/upload
    if (typeof window != "undefined") {
      console.log("chuncks:", this.chunks);
      const data = new Blob(this.chunks, {});
      audioLog.logRecorder(
        "Prepare audio for playback [create blob]",
        data,
      );
      this.onRecordingComplete(data);
    }
  };
}
