import axios from 'axios';
import { Device } from 'mediasoup-client';
import { createTransport } from './mediasoup-api-client';

/**
 * in sync with live-translate-service
 */
export const supportedLanguages = [
  'German',
  'English',
  'Spanish',
  'French',
  'Russian',
  'Italian',
  'Ukrainian',
] as const;
export type Language = typeof supportedLanguages[number];

export const translateTrack = async (options: {
  device: Device;
  sourceTrack: MediaStreamTrack;
  sourceLanguage: Language;
  targetLanguage: Language;
  apiToken: string;
  apiUrl?: string;
}) =>
  new Promise<{ translatedTrack: MediaStreamTrack }>(async (resolve) => {
    const {
      device,
      sourceTrack,
      sourceLanguage,
      targetLanguage,
      apiToken,
      apiUrl = 'http://live-translate-api.cloud-services.linkbox.de:8000',
    } = options;

    console.log('client: starting');

    const routerRtpCapabilities = await axios
      .get(`${apiUrl}/rtp-capabilities`)
      .then((res) => res.data);

    if (!device.loaded) {
      await device.load({
        routerRtpCapabilities,
      });
    }

    console.log(
      'client: loaded device, can produce audio:',
      device.canProduce('audio'),
    );

    const sendTransport = await createTransport(
      device,
      'send',
      apiUrl,
      apiToken,
    );
    console.log('client: created send transport on server', sendTransport.id);

    // "produce" is emitted upon each call to transport.produce()
    sendTransport.on('produce', async (data, callback, errback) => {
      console.log('client: producing', data.rtpParameters);

      console.log(
        `[POST] "${apiUrl}/transports/${sendTransport.id}/translation-producer"`,
      );
      const producer: { producerId: string } = await axios
        .post(`${apiUrl}/transports/${sendTransport.id}/translation-producer`, {
          kind: 'audio',
          rtpParameters: data.rtpParameters,
          apiToken,
          sourceLanguage,
          targetLanguage,
        })
        .then((res) => {
          return res.data;
        })
        .catch((err) => {
          console.error('client: error creating producer', err);
          errback(err);
        });

      console.log('client: produced', producer);

      callback({ id: producer.producerId });
    });

    if (!device.canProduce('audio')) {
      console.error('client: cannot produce audio');
      return;
    }

    sendTransport.observer.on('newproducer', (producer) => {
      console.log('new producer created [id:%s]', producer.id);
    });

    const producer = await sendTransport.produce({
      track: sourceTrack,
    });
    console.log('GOT PRODUCER', producer.id);

    producer.on('trackended', () => {
      console.log('TRACK ENDED');
    });

    producer.on('transportclose', () => {
      console.log('TRANSPORT CLOSED!');
    });

    /////////////// CONSUME ////////////////
    const recvTransport = await createTransport(
      device,
      'recv',
      apiUrl,
      apiToken,
    );
    recvTransport.observer.on('newconsumer', (consumer) => {
      console.log('new consumer created [id:%s]', consumer.id);
    });

    const serverConsumer: { id: string; rtpParameters: any } = await axios
      .post(`${apiUrl}/transports/${recvTransport.id}/consume`, {
        producerId: producer.id,
        apiToken,
      })
      .then((res) => res.data);

    console.log('serverConsumer', serverConsumer);

    const consumer = await recvTransport.consume({
      id: serverConsumer.id,
      producerId: producer.id,
      rtpParameters: serverConsumer.rtpParameters,
      kind: 'audio',
    });

    consumer.on('transportclose', () => {
      console.log('CONSUMER TRANS CLOSED');
    });

    consumer.on('trackended', () => {
      console.log('TRACK ENDED');
    });

    resolve({ translatedTrack: consumer.track });

    recvTransport.on('connectionstatechange', async (state) => {
      console.log('client: recv transport connection state', state);
      if (state === 'connected') {
        console.log('client: connected');
      }
    });
  });
