import { PassThrough } from 'stream';
import { EventEmitter } from 'events';
import fetchPonyfill from 'fetch-ponyfill';
import { DoFetchBody, processRequest } from '../../packages/request';
import * as AllPlatformsCommon from '../../common';
import { Configuration, DEFAULT_BASE_URL } from './common';
import { createTextToSpeech, CreateTextToSpeechParams } from './features/tts';
import { getVoices } from './features/voice';

export interface PlatformEventEmitter extends AllPlatformsCommon.PlatformEventEmitter {
  getVoices(): void;
  createTextToSpeech(params: CreateTextToSpeechParams): void;
}

export class PlatformEventEmitterImpl extends EventEmitter implements PlatformEventEmitter {
  readonly getVoices: PlatformEventEmitter['getVoices'];

  readonly createTextToSpeech: PlatformEventEmitter['createTextToSpeech'];

  constructor(configParams: Configuration) {
    super();
    const platformHeaders: Record<string, string> = {
      'XI-API-Key': `Bearer ${configParams.apiKey}`,
    };

    const { fetch: fetchInstance } = fetchPonyfill();
    const doFetch = (method: string, path: string, body?: DoFetchBody) => {
      let finalBody: BodyInit | undefined;
      let finalHeaders = {
        ...platformHeaders,
      };
      if (body) {
        const finalRequest = processRequest(body, finalHeaders);
        finalBody = finalRequest.body;
        if (finalRequest.headers) {
          finalHeaders = finalRequest.headers;
        }
      }

      const theFetchParams: Record<string, unknown> = {
        method,
        headers: finalHeaders,
      };

      if (finalBody) {
        theFetchParams.body = finalBody;
      }

      const url = new URL(
        `/${configParams.apiVersion}${path}`,
        configParams.baseUrl ?? DEFAULT_BASE_URL,
      ).toString();

      this.emit('start', {
        ...theFetchParams,
        url,
      });

      return fetchInstance(url, theFetchParams);
    };

    const consumeStream = async (response: Response) => {
      // eslint-disable-next-line no-restricted-syntax
      for await (const chunk of response.body as unknown as PassThrough) {
        this.emit('data', chunk);
      }
    };

    this.getVoices = getVoices.bind(this, doFetch);
    this.createTextToSpeech = createTextToSpeech.bind(this, doFetch, consumeStream);
  }
}
