import { Injectable } from '@nestjs/common';
import { EventEmitter } from 'events';
import { v4 as uuidv4 } from 'uuid';
import { WebSocket } from 'ws';
import * as fs from 'fs';
import * as path from 'path';
import { Buffer } from 'buffer';
import { promisify } from 'util';

import { PassThrough } from 'stream';
// import * as ffmpeg from 'fluent-ffmpeg';
// import ffmpegPath from 'ffmpeg-static'
// ffmpeg.setFfmpegPath(ffmpegPath as unknown as string);
import ffmpeg = require('fluent-ffmpeg');
import { Readable, Writable } from 'stream';
import moment = require('moment');

export class StreamService extends EventEmitter {
  private ws: WebSocket;
  private expectedAudioIndex: number;
  private audioBuffer: Record<number, any>;
  private streamSid: string;
  private is_pause: boolean;

  constructor(ws: WebSocket) {
    super();
    this.ws = ws;
    this.expectedAudioIndex = 0;
    this.audioBuffer = {};
    this.streamSid = '';
    this.is_pause = false
  }

  // setWebSocket(ws: WebSocket) {
  //   this.ws = ws;
  // }

  setStreamSid(streamSid: string) {
    this.streamSid = streamSid;
    console.log('streamSid', streamSid);
  }

  getStreamSid() {
    return this.streamSid
  }

  async buffer(index: number | null, audio: any) {
    try {
      console.log("INNN")
      // const buffer = Buffer.from(audio, 'base64');
      // audio = buffer;
      audio = await this.convertToMulaw(audio);
      // let folder_path = path.resolve(__dirname + '/assets/' + 'data1.mp3');
      // fs.writeFileSync(folder_path, buffer);
      if (index === null) {
        this.sendAudio(audio);
      } else if (index === this.expectedAudioIndex) {
        this.sendAudio(audio);
        this.expectedAudioIndex++;

        while (this.audioBuffer.hasOwnProperty(this.expectedAudioIndex)) {
          const bufferedAudio = this.audioBuffer[this.expectedAudioIndex];
          this.sendAudio(bufferedAudio);
          this.expectedAudioIndex++;
        }
      } else {
        this.audioBuffer[index] = audio;
      }
    } catch (error) {
      throw error;
    }
  }

  set_pause(pause: boolean) {
    this.is_pause = pause;
    // console.log('streamSid', streamSid);
  }

  get_pause() {
    return this.is_pause
  }

  private sendAudio(audio: any) {
    if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
      console.warn('WebSocket is not open.');
      return;
    }
    if (this.is_pause) {
      console.warn('audio is in progress.');
      return
    }

    // console.timeEnd('Total time in response');
    this.is_pause = true
    this.ws.send(
      JSON.stringify({
        streamSid: this.streamSid,
        event: 'media',
        media: {
          payload: audio.toString('base64'),
        },
      })
    );

    const markLabel = uuidv4();
    this.ws.send(
      JSON.stringify({
        streamSid: this.streamSid,
        event: 'mark',
        mark: {
          name: markLabel,
        },
      })
    );

    this.emit('audiosent', markLabel);
  }

  async convertToMulaw(inputBuffer: Buffer) {
    try {
      let data = await this.convert_buffer(inputBuffer);

      return data;
    } catch (error) {
      throw error;
    }
  }

  async convert_buffer(audioBuffer: any) {
    try {
      const mp3Chunks = [];
      const mp3Stream = new Writable({
        write(chunk, encoding, callback) {
          mp3Chunks.push(chunk);
          callback();
        },
      });
      // const convertToMp3 = promisify((inputStream: any, callback) => {
      //   ffmpeg()
      //     .input(inputStream)
      //     // .inputFormat('s16le')
      //     .audioCodec('pcm_mulaw')
      //     .audioFrequency(8000)
      //     // .audioChannels(1)
      //     .toFormat('mulaw')
      //     .on('end', callback)
      //     .pipe(mp3Stream, { end: true });
      // });

      const convertToMp3 = promisify((inputStream, callback) => {
        ffmpeg()
          .input(inputStream)
          .inputFormat('s16le') // Raw PCM audio format
          .audioCodec('pcm_mulaw') // Using standard PCM codec
          .audioFrequency(16000)  // Set to a common speech frequency (16 kHz)
          .audioChannels(1)       // Mono audio for speech (or change to 2 for stereo if needed)
          .toFormat('mulaw')        // Output in MP3 format
          .on('end', callback)
          .on('error', (err) => {
            console.error('ffmpeg error:', err);
            callback(err);  // Pass the error to the callback
          })
          .pipe(mp3Stream, { end: true });
      });

      console.log('Convert Mp3---------', convertToMp3);
      const audioStream = new Readable();
      audioStream.push(audioBuffer);
      audioStream.push(null);
      await convertToMp3(audioStream);

      // Assuming your array of buffers is stored in a variable named `bufferArray`
      // console.log('mp3Chunks', mp3Chunks);

      const combinedBuffer = Buffer.concat(mp3Chunks);
      // console.log('combinedBuffer', combinedBuffer);

      return combinedBuffer;
    } catch (error) {
      throw error;
    }
  }

  private sendText(text: string) {
    if (!this.ws || this.ws.readyState !== this.ws.OPEN) {
      console.warn('WebSocket is not open.');
      return;
    }
  
    this.ws.send(
      JSON.stringify({
        streamSid: this.streamSid,
        event: 'text',
        message: text,
      })
    );
  
    console.log(`Text message sent: ${text}`);
  }
  
}
