import { HttpRequest, HttpStatusCodes } from '../base';
import { AUTH_TOKEN } from '../commands';
import Chainable = Cypress.Chainable;

interface ClientCredentials {
  clientId: string;
  clientSecret: string;
}

export interface ClientOAuthToken {
  token: string;
  type: string;
}

Cypress.Commands.add('getClientOAuthTokenForReedMackay', () =>
  getClientOAuthTokenForReedMackay()
);

function getClientOAuthTokenForReedMackay(): Chainable<ClientOAuthToken> {
  cy.allure().logStep('Getting client OAuth token for Reed & Mackay');

  if (AUTH_TOKEN) {
    return getReedMackayClientCredentials().then(generateClientOAuthToken);
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function getReedMackayClientCredentials(): Chainable<ClientCredentials> {
  cy.allure().logStep('Getting Reed & Mackay auth credentials');
  const REED_MACKAY_PROVIDER = 'REED_MACKAY';

  return cy
    .request({
      method: HttpRequest.Post,
      url: '/ta-auth/api/admin/tmc/reedmackay/v1/clientCredentials',
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true,
      body: {
        provider: REED_MACKAY_PROVIDER
      }
    })
    .then(({ status, body }) => {
      expect(status).to.equal(HttpStatusCodes.Ok);

      return { clientId: body.clientId, clientSecret: body.clientSecret };
    });
}

function generateClientOAuthToken(
  credentials: ClientCredentials
): Chainable<ClientOAuthToken> {
  cy.allure().logStep('Generating OAuth token for client');

  return cy
    .request({
      method: HttpRequest.Post,
      url: '/ta-auth/oauth/token',
      retryOnStatusCodeFailure: true,
      qs: {
        grant_type: 'client_credentials',
        client_id: credentials.clientId,
        client_secret: credentials.clientSecret
      }
    })
    .then(({ status, body }) => {
      expect(status).to.equal(HttpStatusCodes.Ok);

      return { token: body.access_token as string, type: body.token_type as string };
    });
}
