import { Random } from '@utility-lib/random';
import { AdminClaim } from '@growth-lib/admin-claim';
import { stagingUsers } from '@fixtures/staging-users';
import { getSignUpToken, loginRequest } from '../../../artifacts';

const API_USERS_BULK = 'api/admin/users/bulk';
const API_USERS = 'api/admin/users?enabled=true&page=0&size=10';
const SIGNUP_URL = 'app/user2/signup';
const API_USERS_BASE = 'api/admin/users';
const API_EXPENSE = 'api/liquid/admin/users';

const { superAdmin } = stagingUsers;
const superAdminCredentials = Cypress.env('superAdmin').SUPER_ADMIN_PASSWORD;
const emailSuperAdmin = superAdmin.email;

interface User {
  uuid: string;
  email: string;
}

interface UsersResponse {
  _embedded: {
    users: User[];
  };
}

export class AddUser {
  static inviteNewUser(email: string) {
    const userData = [
      {
        givenName: 'test',
        familyName: 'test',
        email
      }
    ];

    return cy.request({
      method: 'POST',
      url: API_USERS_BULK,
      body: userData,
      headers: {
        Authorization: 'TripActions ' + AdminClaim.interceptedToken.replace('TripActions ', '')
      },
      retryOnStatusCodeFailure: false
    });
  }

  static fetchUsers(): Cypress.Chainable<Cypress.Response<UsersResponse>> {
    return cy.request({
      method: 'GET',
      url: API_USERS,
      headers: {
        Authorization: 'TripActions ' + AdminClaim.interceptedToken
      }
    });
  }

  static fetchUsersLiquid(): Cypress.Chainable<Cypress.Response<UsersResponse>> {
    return cy.request({
      method: 'GET',
      url: `${API_EXPENSE}?enabled=true`,
      headers: {
        Authorization: 'TripActions ' + AdminClaim.interceptedToken
      }
    });
  }

  static updateUserRoleToAdmin(user: User): Cypress.Chainable<Cypress.Response<any>> {
    return cy.request({
      method: 'PATCH',
      url: `${API_USERS_BASE}/${user.uuid}`,
      body: { admin: true },
      headers: {
        Authorization: 'TripActions ' + AdminClaim.interceptedToken
      },
      retryOnStatusCodeFailure: false
    });
  }

  static updateUserRoleToExpenseAdmin(user: User): Cypress.Chainable<Cypress.Response<any>> {
    return cy.request({
      method: 'PATCH',
      url: `${API_EXPENSE}/${user.uuid}/roles`,
      body: {
        liquidAdmin: true,
        liquidAdminRo: false
      },
      headers: {
        Authorization: 'TripActions ' + AdminClaim.interceptedToken,
        'Content-Type': 'application/json'
      },
      retryOnStatusCodeFailure: false
    });
  }

  static inviteAndAdminUser(): Cypress.Chainable {
    let activeToken = '';
    const email: string = 'user' + '_' + Random.randomString() + '@staging.tripactions.xyz';

    return this.inviteNewUser(email)
      .then((response) => {
        expect(response.status).to.eq(200);
        return this.fetchUsers();
      })
      .then((response) => {
        const user = response.body._embedded.users.find((user) => user.email === email);
        if (!user) {
          console.error(`No user found with email ${email}`);
          throw new Error(`No user found with email ${email}`);
        }
        return this.updateUserRoleToAdmin(user);
      })
      .then((response) => {
        expect(response.status).to.eq(200);
        return loginRequest(emailSuperAdmin, superAdminCredentials, true);
      })
      .then((token) => {
        activeToken = token;
        return getSignUpToken(activeToken, email);
      })
      .then((tokenResponse) => {
        const url = `${SIGNUP_URL}?token=${tokenResponse.body}&email=${encodeURIComponent(tokenResponse.email)}`;
        cy.wait(2000);
        cy.visit(url);
      });
  }

  static visitSignUpUrlWithToken(tokenResponse: any): void {
    const url = `${SIGNUP_URL}?token=${tokenResponse.body}&email=${encodeURIComponent(tokenResponse.email)}`;
    cy.visit(url);
  }

  static inviteAndExpenseAdminUser(): Cypress.Chainable {
    let activeToken = '';
    const email: string = 'user' + '_' + Random.randomString() + '@staging.tripactions.xyz';

    return this.inviteNewUser(email)
      .then((response) => {
        expect(response.status).to.eq(200);
        cy.wait(10000); // Waiting for the Liquid User ID to be created, as it takes some time.
        return this.fetchUsersLiquid();
      })
      .then((response) => {
        const user = response.body._embedded.users.find((user) => user.email === email);
        if (!user) {
          console.error(`No user found with email ${email}`);
          throw new Error(`No user found with email ${email}`);
        }
        return this.updateUserRoleToExpenseAdmin(user);
      })
      .then((response) => {
        expect(response.status).to.eq(200);
        return loginRequest(emailSuperAdmin, superAdminCredentials, true);
      })
      .then((token) => {
        activeToken = token;
        return getSignUpToken(activeToken, email);
      })
      .then((tokenResponse) => {
        this.visitSignUpUrlWithToken(tokenResponse);
      });
  }
}
