import {
  SubscribeMessage,
  WebSocketGateway,
  WebSocketServer,
  WsResponse,
  OnGatewayConnection,
  OnGatewayDisconnect,
  MessageBody,
  ConnectedSocket,
} from '@nestjs/websockets';
import { from, Observable } from 'rxjs';
import { map } from 'rxjs/operators';
import { Server, WebSocket } from 'ws';
import { StreamService } from '../services/stream.service';
import { TranscriptionService } from '../services/transcription.service';
import { TextToSpeechService } from '../services/tts.service';
import { RagService } from '../rag/rag.service';
import { CallService } from '../call/call.service';
import moment from 'moment';

@WebSocketGateway()
export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
  @WebSocketServer()
  server: Server;

  constructor(
    private ragService: RagService,
    private CallService: CallService
  ) { }

  handleConnection(client: WebSocket) {
    console.log('Client connected');
    const streamService = new StreamService(client);
    const transcriptionService = new TranscriptionService();
    const ttsService = new TextToSpeechService();
    client.on('message', async (data: any) => {
      const msg = JSON.parse(data);
      //   client.send(JSON.stringify({ event: 'ack', ack: 'ok' }));
      if (msg.event === 'start') {
        console.log('msg', msg);
        const { streamSid, callSid } = msg.start;
        streamService.setStreamSid(streamSid);
        transcriptionService.setStreamSid(streamSid);
        // this.gptService.setCallSid(callSid);
        this.CallService.save_call({ call_id: callSid, stream_id: streamSid });
        let response = {
          partialResponseIndex: null,
          partialResponse:
            'Hello! i am an ai assistance from henceforth solution. just want to let you know can delay for few seconds after your query but i will answer the best as per my knowledge',
        };
        ttsService.generate(response, 0);
        await this.CallService.save_call_transcript({
          stream_id: streamSid,
          text: response.partialResponse,
          role: 'model',
        });
      } else if (msg.event === 'media') {

        if (!streamService.get_pause()) {
          transcriptionService.send(msg.media.payload);
        } else {
          transcriptionService.keep_alive();
        }

      } else if (msg.event === 'mark') {
        const label = msg.mark.name;
        streamService.set_pause(false);

        console.log(`Twilio -> Audio completed mark: ${label}`);
      } else if (msg.event === 'stop') {
        // console.log(`Twilio -> Media stream ended.`);
        // console.log("msg.stop", msg.stop);
        console.log('msg.stop', msg);
        let { streamSid } = msg;
        this.CallService.update_call({
          stream_id: streamSid,
          status: 'COMPLETE',
        });
        this.CallService.call_summerize({ stream_id: streamSid });
      }
    });

    ttsService.on('speech', (responseIndex, audio, label, icount) => {
      // console.log(`Interaction ${icount}: TTS -> TWILIO: ${label}`);

      streamService.buffer(responseIndex, audio);
    });

    transcriptionService.on('transcription', async (text) => {
      if (!text) {
        return;
      }
      console.time('Total time in response');
      console.log("text:", text);

      let stream_id = await transcriptionService.getStreamSid();
      await this.CallService.save_call_transcript({
        stream_id: stream_id,
        text: text,
        role: 'user',
      });
      this.CallService.update_call({
        stream_id: stream_id,
        last_message: text,
      });

      // console.log(`Interaction ${'interactionCount'} – STT -> GPT: ${text}`);
      // gptService.completion(text, interactionCount);
      // interactionCount += 1;
      let chat_history = await this.CallService.chat_history(stream_id);

      // console.time('Total time in gemini response');
      let data = await this.ragService.getAnswerRag(text, chat_history);
      // console.timeEnd('Total time in gemini response');

      await this.CallService.save_call_transcript({
        stream_id: stream_id,
        text: data.answer,
        role: 'model',
      });

      // console.log('gpt-rply', data);
      ttsService.generate(
        {
          partialResponseIndex: null,
          partialResponse: data.answer,
        },
        0
      );
    });

    transcriptionService.on('utterance', async (text) => {
      if (!text) {
        return;
      }
      // console.log(`utterance: ${text}`);
      // console.log("utterance moment()", moment().format());

      // gptService.completion(text, interactionCount);
      // interactionCount += 1;
    });

    transcriptionService.on('call_end', async (data) => {
      console.log('call_end', data);
      let { stream_id, metadata } = data;
      let { duration } = metadata;
      this.CallService.update_call({ stream_id, call_duration: duration });
    });

    client.on('error', (error) => console.error('WebSocket error:', error));
    client.on('close', () => console.log('Client disconnected'));
  }

  handleDisconnect(client: WebSocket) {
    console.log('Client disconnected');
  }
}
