/**
 * Copyright (C) 2020-2021  The Software Heritage developers
 * See the AUTHORS file at the top-level directory of this distribution
 * License: GNU Affero General Public License version 3, or any later version
 * See top-level LICENSE file for more information
 */

describe('Test API tokens UI', function() {

  it('should ask for user to login', function() {
    cy.visit(`${this.Urls.oidc_profile()}#tokens`, {failOnStatusCode: false});
    cy.location().should(loc => {
      expect(loc.pathname).to.eq(this.Urls.oidc_login());
    });
  });

  function initTokensPage(Urls, tokens) {
    cy.intercept(`${Urls.oidc_list_bearer_tokens()}/**`, {
      body: {
        'recordsTotal': tokens.length,
        'draw': 2,
        'recordsFiltered': tokens.length,
        'data': tokens
      }
    });
    // the tested UI should not be accessible for standard Django users
    // but we need a user logged in for testing it
    cy.adminLogin();
    cy.visit(`${Urls.oidc_profile()}#tokens`);
  }

  it('should initiate token generation flow', function() {
    initTokensPage(this.Urls, []);

    cy.contains('Generate new token')
      .click();

    cy.get('.modal-dialog')
      .should('be.visible');

    cy.get('.modal-header')
      .should('contain', 'Bearer token generation');

    cy.get('#swh-token-form-submit')
      .click();

    cy.location().should(loc => {
      expect(loc.pathname).to.eq(this.Urls.oidc_generate_bearer_token());
    });
  });

  it('should report error when not logged in and visiting a token generation URL', function() {
    cy.visit(this.Urls.oidc_generate_bearer_token_complete(), {failOnStatusCode: false});
    cy.get('.swh-http-error')
      .should('be.visible');
    cy.get('.swh-http-error-code')
      .should('contain', 403);
    cy.get('.swh-http-error-desc')
      .should('contain', 'You are not allowed to generate bearer tokens');
  });

  function displayToken(Urls, status, body = '') {
    cy.intercept('POST', `${Urls.oidc_get_bearer_token()}/**`, {
      body: body,
      statusCode: status
    }).as('getTokenRequest');

    cy.contains('Display token')
      .click({force: true});

    cy.get('.modal-dialog')
      .should('be.visible');

    cy.get('.modal-header')
      .should('contain', 'Display bearer token');
  }

  it('should show a token when requested', function() {
    initTokensPage(this.Urls, [{id: 1, creation_date: new Date().toISOString()}]);
    const tokenValue = 'token-value';
    displayToken(this.Urls, 200, tokenValue);
    cy.get('#swh-bearer-token')
      .should('contain', tokenValue);
  });

  it('should report error when token display failed', function() {
    initTokensPage(this.Urls, [{id: 1, creation_date: new Date().toISOString()}]);
    const errorMessage = 'Internal server error';
    displayToken(this.Urls, 500, errorMessage);
    cy.get('.modal-body')
      .should('contain', errorMessage);
  });

  it('should report error when token expired', function() {
    initTokensPage(this.Urls, [{id: 1, creation_date: new Date().toISOString()}]);
    const errorMessage = 'Bearer token has expired';
    displayToken(this.Urls, 400, errorMessage);
    cy.get('.modal-body')
        .should('contain', errorMessage);
  });

  function revokeToken(Urls, status) {
    cy.intercept('POST', `${Urls.oidc_revoke_bearer_tokens()}/**`, {
      body: '',
      statusCode: status
    }).as('revokeTokenRequest');

    cy.contains('Revoke token')
      .click({force: true});

    cy.get('.modal-dialog')
      .should('be.visible');

    cy.get('.modal-header')
      .should('contain', 'Revoke bearer token');

    cy.get('#swh-token-form-submit')
      .click({force: true});

    cy.wait('@revokeTokenRequest');

    if (status === 200) {
      cy.get('#swh-token-form-submit')
        .should('be.disabled');
    }
  }

  it('should revoke a token when requested', function() {
    initTokensPage(this.Urls, [{id: 1, creation_date: new Date().toISOString()}]);
    revokeToken(this.Urls, 200);
    cy.get('#swh-token-form-message')
      .should('contain', 'Bearer token successfully revoked');
  });

  it('should report errors when token revoke failed', function() {
    initTokensPage(this.Urls, [{id: 1, creation_date: new Date().toISOString()}]);
    revokeToken(this.Urls, 500);
    cy.get('#swh-token-error-message')
      .should('contain', 'Internal server error');
  });

});
