import { factory, Interface } from '@admin-factory/index';
import { AUTH_TOKEN } from '../commands';
import { stagingUsers } from '@fixtures/staging-users';
import { SuperAdminClient } from '@support-onboard/lib';
import { LiquidClient } from '@support-liquid/lib';
import { HttpStatusCodes } from 'cypress/support/base';
import { createLegalEntityEU, addOfficeEU } from '../../artifacts/base/organization_EU';
import { SplitUtility } from 'cypress/support/split/split_utility';
import { Timeouts } from '@utility-lib/constants';
import Chainable = Cypress.Chainable;

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

Cypress.Commands.add('createGuestInvitePaymentMethod', () => {
  const body = factory.createPaymentMethod();
  createPaymentMethodRequest(body);
});

Cypress.Commands.add('deletePaymentMethod', () => {
  cy.task('getDataFromCache', 'paymentMethodId').then((id: any) => {
    deletePaymentMethodRequest(id);
  });
});

Cypress.Commands.add('revokeInvitation', () => {
  cy.updateSplits();

  SplitUtility.isSplitOn('GROUP_TRAVEL_REFACTOR').then((refactored) => {
    if (refactored) {
      cy.task('getDataFromCache', 'tripInvitationId').then((id: any) => {
        revokeGuestTravelRequest(id);
      });
    } else {
      cy.task('getDataFromCache', 'tripInvitationId').then((id: any) => {
        revokeInvitationRequest(id);
      });
    }
  });
});

Cypress.Commands.add('createGuestInvite', (guestInvite) => {
  createGuestInviteRequest(guestInvite);
});

Cypress.Commands.add('createGuestTravel', (guestInvite) => {
  createGuestTravelRequest(guestInvite);
});

Cypress.Commands.add('ticketFlightBooking', (bookingUuid: string) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => ticketFlightBookingRequest(bookingUuid));
});

Cypress.Commands.add('ticketFlightBookingWithoutLogin', (bookingUuid: string) => {
  ticketFlightBookingRequest(bookingUuid);
});

Cypress.Commands.add('forcePDFSyncAPI', (bookingUuid: string) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => forcePDFSyncAPI(bookingUuid));
});

Cypress.Commands.add('forceSyncAPI', (bookingUuid: string) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => forceSyncAPI(bookingUuid));
});

Cypress.Commands.add(
  'addAmexBTAEUPaymentUuId',
  (paymentMethodUuId: string, amexBTAPlatformType: string) => {
    cy.loginWithAuthToken({
      email: superAdmin.email,
      password: superAdminCredentials,
      isSA: true
    }).then(() => addAmexBTAEUPaymentUuId(paymentMethodUuId, amexBTAPlatformType));
  }
);
Cypress.Commands.add('getAmexBTAEuXML', (amexBTARegion: string) => {
  cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => getAmexBTAEuXML(amexBTARegion));
});
Cypress.Commands.add('getLedgerData', (bookingUuid: string) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => getLedgerData(bookingUuid));
});

Cypress.Commands.add('callLiquidAPI', (api: any) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => callLiquidAPI(api));
});

const performAuthenticatedAction = (
  liquidAdminEmail: any,
  liquidAdminPassword: any,
  action: any
) => {
  cy.loginWithAuthToken({
    email: liquidAdminEmail,
    password: liquidAdminPassword,
    isSA: true
  }).then(() => action());
};

Cypress.Commands.add('getLiquidStatementID', (liquidAdminEmail, liquidAdminPassword) =>
  performAuthenticatedAction(liquidAdminEmail, liquidAdminPassword, getLiquidStatement)
);

Cypress.Commands.add('requestBulkDownloadAPI', (liquidAdminEmail, liquidAdminPassword) =>
  performAuthenticatedAction(
    liquidAdminEmail,
    liquidAdminPassword,
    requestBulkDownloadAPI
  )
);

Cypress.Commands.add('bulkDownloadAPI', (liquidAdminEmail, liquidAdminPassword) =>
  performAuthenticatedAction(liquidAdminEmail, liquidAdminPassword, bulkDownloadAPI)
);

Cypress.Commands.add(
  'ticketAndSyncFlightBooking',
  (bookingUuid: string, agencyData: string, flightBookingId: string) => {
    cy.loginWithAuthToken({
      email: superAdmin.email,
      password: superAdminCredentials,
      isSA: true
    })
      .then(() => ticketFlightBookingRequest(bookingUuid))
      .then(() => syncFlightBookingRequest(agencyData, flightBookingId));
  }
);
Cypress.Commands.add(
  'sabreSyncFlightBooking',
  (agencyData: string, flightBookingId: string) => {
    cy.loginWithAuthToken({
      email: superAdmin.email,
      password: superAdminCredentials,
      isSA: true
    }).then(() => syncFlightBookingRequest(agencyData, flightBookingId));
  }
);

Cypress.Commands.add('retrieveDownloadPDF', (bookingUuid: string) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => retrieveBookingPDF(bookingUuid));
});

Cypress.Commands.add(
  'createCompanyLegalEntity',
  (adminEmail, adminPassword, legalEntitiesData) => {
    cy.loginWithAuthToken({
      email: adminEmail,
      password: adminPassword,
      isSA: true
    }).then(() => createCompanyLegalEntity(legalEntitiesData));
  }
);
Cypress.Commands.add('createCompanyOffice', (adminEmail, adminPassword) => {
  cy.loginWithAuthToken({
    email: adminEmail,
    password: adminPassword,
    isSA: true
  }).then(() => createCompanyOffice());
});

Cypress.Commands.add('deleteCompany', (companyUuid) => {
  cy.loginWithAuthToken({
    email: superAdmin.email,
    password: superAdminCredentials,
    isSA: true
  }).then(() => deleteCompany(companyUuid));
});

function createPaymentMethodRequest(body: Interface.PaymentMethod) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: '/api/admin/paymentMethods',
      headers: {
        Authorization: AUTH_TOKEN
      },
      body,
      retryOnStatusCodeFailure: true
    }).then(({ body, status }) => {
      expect(status, 'Created Payment method').to.equal(201);
      cy.task('putDataInCache', { key: 'paymentMethodId', data: body.uuid });
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function deletePaymentMethodRequest(paymentId: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'DELETE',
      url: `/api/admin/paymentMethods/${paymentId}`,
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'Payment method ID deleted').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function callLiquidAPI(apiEndpoint: string) {
  let apiEndpointString;
  if (apiEndpoint == 'liquidDelegate') {
    apiEndpointString = LiquidClient.callLiquidDelegateAPI;
  } else if (apiEndpoint == 'liquidUserMe') {
    apiEndpointString = LiquidClient.callLiquidMEAPI;
  } else if (apiEndpoint == 'liquidUserSearchHome') {
    apiEndpointString = LiquidClient.callLiquidHomeAPI;
  } else {
    apiEndpointString = LiquidClient.callProfileAPI;
  }
  if (AUTH_TOKEN) {
    cy.request({
      method: 'GET',
      url: apiEndpointString,
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ body, status }) => {
      expect(status, 'liquid response').to.equal(HttpStatusCodes.Ok);
      return body;
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function getLiquidStatement() {
  cy.allure().logStep('Get Liquid Statements');
  if (AUTH_TOKEN) {
    cy.request({
      method: 'GET',
      url: LiquidClient.getLiquidStatements,
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then((response) => {
      expect(response.status, 'liquid response').to.equal(HttpStatusCodes.Ok);
      // Pick up the first statement that actually has transactions
      // const firstStatement = response.body?._embedded?.statements?.filter(
      //   (statement: { transactions: number }) => statement.transactions !== 0
      // );
      // Hard code the statement ID for now
      const firstStatement = { uuid: 'cc2e0fe6-f720-45e7-a169-31f98fe94313' };
      if (firstStatement) {
        const firstUUID = firstStatement.uuid;
        cy.task('putDataInCache', {
          key: 'statementID',
          data: firstUUID
        });
      } else {
        throw new Error('No Statement UUID Found');
      }
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
function requestBulkDownloadAPI() {
  cy.allure().logStep('Request for Bulk download API by statement ID');
  if (AUTH_TOKEN) {
    // Retrieve the statementId from the cache
    cy.task('getDataFromCache', 'statementID').then((statementID) => {
      if (statementID) {
        const statementIdString = statementID as string;
        cy.log('-----------------------' + statementIdString); // Explicitly cast statementId to string
        cy.request({
          method: 'GET',
          url: LiquidClient.requestBulkDownload.replace(
            '{statementUuid}',
            statementIdString
          ),
          headers: {
            Authorization: AUTH_TOKEN
          },
          retryOnStatusCodeFailure: true
        }).then((response) => {
          expect(response.status, 'liquid response').to.equal(HttpStatusCodes.Ok);
        });
      } else {
        throw new Error('No statementID found in the cache.');
      }
    });
  } else {
    throw new Error('Please login before calling API endpoints');
  }
}
function bulkDownloadAPI() {
  cy.allure().logStep('Get BulkDownload s3 link by statement ID');
  if (AUTH_TOKEN) {
    // Retrieve the statementId from the cache
    cy.task('getDataFromCache', 'statementID').then((statementID) => {
      if (statementID) {
        const statementIdString = statementID as string;
        cy.request({
          method: 'GET',
          url: LiquidClient.bulkDownload.replace('{statementUuid}', statementIdString),
          headers: {
            Authorization: AUTH_TOKEN
          },
          retryOnStatusCodeFailure: true
        }).then((response) => {
          expect(response.status, 'liquid response').to.equal(HttpStatusCodes.Ok);
          cy.task('putDataInCache', {
            key: 'bulkDownload',
            data: response.body
          });
        });
      } else {
        throw new Error('No statementID found in the cache.');
      }
    });
  } else {
    throw new Error('Please login before calling API endpoints');
  }
}

function forcePDFSyncAPI(bookingUuid: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'GET',
      url: SuperAdminClient.forcePDFSyncAPI.replace('{bookingUuid}', bookingUuid),
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'force pdf sync').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
function forceSyncAPI(bookingUuid: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'GET',
      url: SuperAdminClient.forceSync.replace('{bookingUuid}', bookingUuid),
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      cy.log('force sync API call is triggered');
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
function addAmexBTAEUPaymentUuId(paymentMethodUuId: string, amexBTAPlatformType: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: SuperAdminClient.addAmexBTAPaymentUuId
        .replace('{paymentMethodUuId}', paymentMethodUuId)
        .replace('{amexBTAPlatform}', amexBTAPlatformType),
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'adding Amex card payment method UUID in the tools').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
function getAmexBTAEuXML(amexBTARegion: string) {
  if (AUTH_TOKEN) {
    const now = new Date();
    const fromTime = new Date(now.getTime() - 2 * 60 * 1000); // 2 min ago
    const dateFrom = fromTime.toISOString();
    const dateTo = now.toISOString();
    const requestBody = {
      dateFrom: dateFrom,
      dateTo: dateTo
    };
    cy.request({
      method: 'POST',
      url: SuperAdminClient.getAmexBTAEuXML.replace('{amexBTARegion}', amexBTARegion),
      body: requestBody,
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then((response) => {
      cy.log(
        'AMEX BTA req body: ' + requestBody.dateFrom + 'To:------' + requestBody.dateTo
      );
      expect(response.status).to.equal(200);
      cy.task('putDataInCache', {
        key: 'AmexBTAEuXML',
        data: response.body
      });
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
function getLedgerData(bookingUuid: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'GET',
      url: SuperAdminClient.getLedgerData.replace('{bookingUuid}', bookingUuid),
      headers: {
        Authorization: AUTH_TOKEN,
        'Content-Type': 'application/json'
      },
      retryOnStatusCodeFailure: true
    }).then((response) => {
      expect(response.status, 'get ledger data').to.equal(200);
      cy.task('putDataInCache', {
        key: 'ledgerData',
        data: response.body
      });
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function ticketFlightBookingRequest(bookingUuid: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: SuperAdminClient.ticketFlightBooking.replace('{bookingUuid}', bookingUuid),
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: false,
      failOnStatusCode: false,
      timeout: 120000
    }).then(({ status }) => {
      if (status === 200) {
        cy.log('super admin ticket booking request - success');
      } else {
        cy.log('super admin ticket booking request - failure with code ' + status);
      }
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function retrieveBookingPDF(bookingUuid: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: SuperAdminClient.retrieveBookingPDF.replace('{bookingUuid}', bookingUuid),
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'retrieveBookingPDF').to.equal(200);
    });
  } else {
    throw new Error('retrieveBookingPDF : Please login before calling api endpoints');
  }
}

function syncFlightBookingRequest(agencyData: string, flightBookingId: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'PUT',
      url: SuperAdminClient.syncFlightBooking
        .replace('{agencyData}', agencyData)
        .replace('{flightBookingId}', flightBookingId),
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'Sync Sabre flight booking').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function revokeInvitationRequest(invitationId: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: `/api/admin/tripInvitations/${invitationId}/revoke`,
      headers: {
        Authorization: AUTH_TOKEN
      },
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'Invitation is revoked').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function revokeGuestTravelRequest(invitationId: string) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: `/api/v1/user/travel-events/${invitationId}/cancel`,
      headers: {
        Authorization: AUTH_TOKEN
      },
      failOnStatusCode: false
    }).then(({ status }) => {
      expect(status, 'Invitation is revoked').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function createGuestInviteRequest(body: Interface.GuestInvite) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: '/api/admin/tripInvitations',
      headers: {
        Authorization: AUTH_TOKEN
      },
      body,
      retryOnStatusCodeFailure: true
    }).then(({ status }) => {
      expect(status, 'Created Trip invitation').to.equal(201);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function createGuestTravelRequest(body: any) {
  if (AUTH_TOKEN) {
    cy.request({
      method: 'POST',
      url: '/api/v1/user/guest-travel-events/bulk-create',
      headers: {
        Authorization: AUTH_TOKEN
      },
      body,
      failOnStatusCode: true
    }).then(({ status }) => {
      expect(status, 'Created Guest Travel Event').to.equal(200);
    });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

// by self sell delete api
function deleteCompany(companyUuid: string): Chainable<any> {
  const lsToken = window.localStorage.getItem('tripactions.TripActionsToken');
  // there is a reference problem that AUTH_TOKEN is not getting updated
  const token = AUTH_TOKEN || (lsToken ? `TripActions ${lsToken}` : '');

  if (token) {
    return cy
      .request({
        method: 'DELETE',
        url: 'api/selfSell/superAdmin/companies/' + companyUuid,
        headers: {
          Authorization: token
        },
        failOnStatusCode: true
      })
      .then(({ status }) => {
        expect(
          status,
          `Delete Company by uuid ${companyUuid} with super admin api`
        ).to.equal(200);
      });
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}

function createCompanyLegalEntity(legalEntitiesData: any) {
  if (AUTH_TOKEN) {
    createLegalEntityEU(AUTH_TOKEN, legalEntitiesData);
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
function createCompanyOffice() {
  if (AUTH_TOKEN) {
    addOfficeEU(AUTH_TOKEN, '', true);
  } else {
    throw new Error('Please login before calling api endpoints');
  }
}
