import { JIBESTREAM_DESTINATION, MAP_CREDENTIALS } from 'src/JibestreamTypes';
import { JIBESTREAM_VENUE_PROPERTIES } from './ApiTypes';
import { MAP_LOCALE } from 'src/CommandTypes';

class JibestreamApi {
  async getToken(credentials: {
    clientId: string;
    clientSecret: string;
    customerId: number;
    host: string;
  }): Promise<string | undefined> {
    const details: { [key: string]: string } = {
      client_id: credentials.clientId,
      client_secret: credentials.clientSecret,
      grant_type: 'client_credentials',
    };

    var formBody = [];
    for (var property in details) {
      var encodedKey = encodeURIComponent(property);
      var encodedValue: string = encodeURIComponent(details[property]!);
      formBody.push(encodedKey + '=' + encodedValue);
    }
    const body = formBody.join('&');

    const options: RequestInit = {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
      },
      body: body,
    };
    try {
      return await fetch(`${credentials.host}/JACS/api/auth/token`, options)
        .then(async (response) => {
          if (!response.ok) {
            console.error(
              'Request failed with status code ' +
                response.status +
                ': ' +
                response.statusText
            );
            if (response.status === 401) {
              console.error('Authentication failed for getToken');
            } else if (response.status === 403) {
              console.error('Authorization failed for getToken');
            } else {
              console.log(
                'Error in getToken, with status code ' + response.status
              );
            }
            return undefined;
          }
          const resp: { access_token: string; expires_in: number } =
            await response.json();
          return resp.access_token;
        })
        .catch((error: Error) => {
          console.error('Fetch request failed. Error: ' + error.message);
          return undefined;
        });
    } catch (e) {
      console.error('Error completing getToken' + e);
      return undefined;
    }
  }

  async getAllDestinations(
    credentials: {
      clientId: string;
      clientSecret: string;
      customerId: number;
      host: string;
      locale?: MAP_LOCALE;
    },
    venueIds: number[]
  ): Promise<{ [venueId: number]: JIBESTREAM_DESTINATION[] }> {
    const token = await this.getToken(credentials);
    console.log('GETTING DESTINATIONS', credentials, venueIds, token);
    if (!token) {
      return {};
    }
    const destinations: { [venueId: number]: JIBESTREAM_DESTINATION[] } = {};
    await Promise.all(
      venueIds.map(async (venueId) => {
        const destinationsCurr: JIBESTREAM_DESTINATION[] | undefined = (
          await this.getVenueProperties(token, { ...credentials, venueId })
        )?.destinations.items;
        if (destinationsCurr !== undefined)
          destinations[venueId] = destinationsCurr;
        return null;
      })
    );
    return destinations;
  }

  async getVenueProperties(
    token: string,
    credentials: MAP_CREDENTIALS
  ): Promise<JIBESTREAM_VENUE_PROPERTIES | undefined> {
    const options: RequestInit = {
      method: 'GET',
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };
    const queryParams = credentials.locale
      ? `?locale=${credentials.locale}`
      : '';
    try {
      return await fetch(
        `${credentials.host}/JACS/api/customer/${credentials.customerId}/venue/${credentials.venueId}/full${queryParams}`,
        options
      )
        .then((response) => {
          if (!response.ok) {
            console.error(
              'Request failed with status code ' +
                response.status +
                ': ' +
                response.statusText
            );
            if (response.status === 401) {
              console.error('Authentication failed for getVenueProperties');
            } else if (response.status === 403) {
              console.error('Authorization failed for getVenueProperties');
            } else {
              console.log(
                'Error in getVenueProperties, with status code ' +
                  response.status
              );
            }
            return undefined;
          }
          const resp = response.json();
          return resp;
        })
        .catch((error: Error) => {
          console.error('Fetch request failed. Error: ' + error.message);
          return undefined;
        });
    } catch (e) {
      console.error('Error completing getVenueProperties' + e);
      return undefined;
    }
  }
}

export const jibestreamApi = new JibestreamApi();
