import { Utility, utilitySelector, Timeouts, Logs } from '@utility-lib/index';
import { hotelCheckoutSelector } from '@hotel-lib/index';
import { RetryRentalCarModel } from '@rentalcar-modal/index';
import { RentalCarDropOffType, RentalCarLocationType } from '@rentalcar-modal/rental_car_utility';
import { LocationParams } from '@rentalcar-modal/retry_factory';
import { Interception } from 'cypress/types/net-stubbing';

type decisionType = 'decline' | 'approve';

export const rentalCarCheckout = {
  saveTripInfo: '[qaid="tripCheckoutCreateButton"]',
  acknowledgement: '[qaid="carCheckoutSummary"] .mat-checkbox-inner-container',
  addToExistingTrip: '[qaid="tripCheckoutAddToTrip"]',
  bookNow: '[qaid="carCheckoutSummary"] .ta-button__content',
  bookingSuccessMsg: '.booking-success .booking-success__left__title',
  requireDataSection: 'ta-checkout-traveler-require-data',
  requireDataEmail: 'ta-checkout-traveler-require-data input[type="email"]',
  requireDataSave: 'ta-checkout-traveler-require-data ta-button[theme="primary"]',
  policyText: 'textarea[qaid="outOfPolicyReason"]',
  outOfPolicyAcknowledgment: '[qaid="carOutOfPolicy"] [formcontrolname="reason"]',
  outOfPolicyContinue: '[headerprimarybuttonlabel="Your policy"] [qaid="infoBannerPrimaryButton"]',
  consentForApproverDecision: '[qaid="carOutOfPolicy"] .mat-checkbox-inner-container',
  confirmApproval: '.hard-approval-explanation-modal [tamodalprimaryaction]',
  appliedLoyalty:
    '.ta-guest-info-loyalty-card .ta-guest-info-loyalty-card__details .ta-guest-info-loyalty-card__details-wrapper .ta-guest-info-loyalty-card__details-text',
  paymentMethodCard: '[class^="ta-payment-card__image"]',
  checkoutSummary: '[qaid="carCheckoutSummary"] [class~="info-banner--none"]',
  checkoutButton: 'ta-button[qaid="infoBannerPrimaryButton"]',
  seeMoreCars: '[class="information__footer"] [class="ta-button__content"]',
  tripCheckoutCreateButton: '[qaid="tripCheckoutCreateButton"]',
  deliveryAndCollectAckCheckBox: '[title="Important booking details"] .mat-checkbox-inner-container',
  deliveryAndCollectAckCheckBoxContinue: '[title="Important booking details"] [class="ta-button__content"]',
  dAndCCheckoutInfo: '[class="car-checkout__important-delivery-collect-details__message"]',
  dAndCBookingInfoHeader: '[class="car-checkout__booking-info__list-heading"]',
  estimatedCost: '.car-checkout__est-total div span'
};

interface CheckoutParams {
  saveBookingId?: boolean;
  rentalCarLocationType?: RentalCarLocationType;
  rentalCarDropOffType?: RentalCarDropOffType;
  invalidCard?: boolean;
}
export class RentalCarCheckout {
  static waitToBeLoaded(): void {
    cy.allure().logStep('wait for cars checkout page APIs to complete');
    cy.wait(['@waitForCarContract', '@waitForPaymentMethods']);
  }

  static waitToBeLoadedForEvent(): void {
    cy.allure().logStep('wait for cars checkout page APIs to complete');
    cy.wait(['@waitForCarContract', '@waitForPaymentMethods']);
  }

  static setTripInfo() {
    cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
    cy.get(rentalCarCheckout.paymentMethodCard).should('be.visible');
    Utility.saveTripInformation();
    const maxRetryCount = 3;
    let retryCount = 0;

    const checkTripInfoLoaded = () => {
      cy.get(utilitySelector.bodySelector).then(($body: JQuery<HTMLElement>) => {
        if ($body.find(rentalCarCheckout.tripCheckoutCreateButton).length > 0) {
          Utility.saveTripInformation();
        } else {
          retryCount++;
          if (retryCount < maxRetryCount) {
            cy.wait(Timeouts.SHORT_TIMEOUT_2_SEC.timeout);
            Utility.saveTripInformation();
          } else {
            retryCount++;
            if (retryCount < maxRetryCount) {
              cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
              Utility.saveTripInformation();
              checkTripInfoLoaded();
            } else {
              cy.log('Trip info is not loaded');
            }
          }
        }
      });
    };

    checkTripInfoLoaded();
  }

  static addToExistingTrip() {
    cy.get(rentalCarCheckout.addToExistingTrip).click();
  }

  static setAcknowledgement() {
    cy.allure().logStep('accept acknowledgement');
    cy.get(rentalCarCheckout.paymentMethodCard).should('be.visible');
    cy.checkIfExist(rentalCarCheckout.acknowledgement);
  }

  static expectLoyaltyToBeApplied(loyaltyName: string) {
    cy.get(rentalCarCheckout.appliedLoyalty).should('be.contain', loyaltyName);
    cy.allure().logStep(`Loyalty ${loyaltyName} is applied`);
  }

  static expectBookingSuccessfully() {
    RentalCarCheckout.expectRentalCarBookingSuccessfully('Car confirmed!');
  }

  static guestCheckOutCar() {
    cy.wait('@waitForPaymentMethods');
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(rentalCarCheckout.checkoutSummary)
      .find(rentalCarCheckout.checkoutButton)
      .contains(' Book now ')
      .then((ele) => {
        cy.wrap(ele).scrollIntoView({ easing: 'linear' });
        cy.wrap(ele).trigger('click', { force: true });
      });
    cy.clickIfExist(rentalCarCheckout.confirmApproval, Timeouts.SHORT_TIMEOUT_3_SEC);
    cy.wait(Timeouts.MEDIUM_TIMEOUT_20_SEC.timeout);
    cy.wait('@waitForBooking');
    cy.allure().logStep('Book car');
  }

  static expectRentalCarBookingSuccessfully(successMsg: string) {
    cy.get(rentalCarCheckout.bookingSuccessMsg, Timeouts.MAX_TIMEOUT_120_SEC).should('be.contain', `${successMsg}`);
    cy.allure().logStep('Car successfully booked');
    RentalCarCheckout.closeBookingSuccessModel();
    cy.allure().logStep('Hotel booked successfully');
  }

  static closeBookingSuccessModel() {
    cy.allure().logStep('close booking success model');
    cy.get(hotelCheckoutSelector.closeBookingSuccessModel, Timeouts.MAX_TIMEOUT_120_SEC).click({
      force: true
    });
  }

  static updateEmailDetails(email: string) {
    cy.get(utilitySelector.bodySelector).then(($body) => {
      if ($body.find(rentalCarCheckout.requireDataSection).length) {
        cy.allure().logStep('enter required email details');
        cy.get(rentalCarCheckout.requireDataEmail).type(email);
        cy.get(rentalCarCheckout.requireDataSave).click();
      }
    });
  }

  static setOutOfPolicyReason() {
    cy.allure().logStep('set out of policy acknowledgment');
    cy.get(rentalCarCheckout.policyText).type('Out of policy Acknowledgment', {
      force: true
    });

    cy.get(utilitySelector.bodySelector).then((acknowledgement) => {
      if (acknowledgement.find(rentalCarCheckout.consentForApproverDecision).length > 0) {
        cy.get(rentalCarCheckout.consentForApproverDecision).click({ force: true });
      }
    });
    cy.get(rentalCarCheckout.outOfPolicyContinue).click({ force: true });
  }

  static adminApproveOrDeclineRentalCarBooking(adminPassword: string, decision: decisionType) {
    cy.allure().logStep(`admin ${decision} rental car booking`);
    cy.task('getDataFromCache', 'userResponse').then((response: any) => {
      cy.setAuthToken({
        email: response.email,
        password: adminPassword,
        localStorage: false
      });
    });
    cy.task('getDataFromCache', 'rentalCarBookingId').then((bookingId: any) => {
      if (decision === 'decline') {
        cy.log('decline booking');
        cy.declineBooking(bookingId);
      } else {
        cy.log('approve booking');
        cy.approveBooking(bookingId);
      }
    });
    cy.url().then((url) => {
      cy.log('Current URL: ' + url);
      cy.task('putDataInCache', {
        key: 'rentalCarTripItineraryUrl',
        data: url
      });
    });
    cy.location().then((location) => {
      cy.log('Current URL: ' + location.href);
    });
  }

  static expectCarTypeIsPresent() {
    cy.task('getDataFromCache', 'selectedCarType').then((carType: any) => {
      cy.get('[class="ta-car-card__car-type"]').should('be.contain', carType);
    });
  }

  static checkOutCar(
    saveBookingId?: boolean,
    rentalCarLocationType?: RentalCarLocationType,
    rentalCarDropOffType?: RentalCarDropOffType,
    invalidCard?: boolean
  ) {
    const maxRetryCount = 3;
    let retryCount = 0;

    const retryCheckout = () => {
      cy.log(`Checkout failed. Retrying... ${retryCount} times`);
      retryCount++;
      if (retryCount < maxRetryCount) {
        retryCarCheckout();
      } else {
        cy.log(`Maximum retry count reached. Checkout failed. Retried ${retryCount} times.`);
      }
    };

    const retryCarCheckout = () => {
      cy.get(rentalCarCheckout.seeMoreCars).eq(1).click();
      cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
      if (rentalCarLocationType && rentalCarDropOffType) {
        const params: LocationParams = {
          tripTileType: 'Personal',
          dropOffType: rentalCarDropOffType,
          pickUpLocation: '',
          rentalCarLocationType: rentalCarLocationType
        };
        RetryRentalCarModel.getLocationDescription(params);
      }
      checkoutCarRequest(true);
    };

    const checkoutCarRequest = (isRetry: boolean) => {
      if (!isRetry && invalidCard) {
        this.expectCarTypeIsPresent();
      }
      cy.get(rentalCarCheckout.bookNow)
        .invoke('text')
        .then((text) => {
          if (text.includes('Book now') || text.includes('Request now')) {
            cy.get(rentalCarCheckout.bookNow).click({ force: true });
          }
        });
      cy.log('click on book now button');
      cy.clickIfExist(rentalCarCheckout.confirmApproval, Timeouts.SHORT_TIMEOUT_3_SEC);
      cy.wait('@waitForRentalCarCheckout').then((xhr: Interception) => {
        if (invalidCard) {
          cy.log('Invalid card');
          RentalCarCheckout.expectDirectBillError(xhr);
        } else {
          cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
          cy.get(utilitySelector.bodySelector).then(($body) => {
            if ($body.find(utilitySelector.warningMsg).length > 0) {
              retryCheckout();
            } else {
              this.handleSuccessfulCheckout();
            }
          });
        }

        cy.wait('@waitForBooking').then((xhr: Interception) => {
          this.handleBookingResponse(xhr, saveBookingId);
        });
      });
    };
    checkoutCarRequest(false);
  }

  static retryCheckout(maxRetryCount: number, retryCount: number, retryCarCheckout: () => void) {
    if (retryCount < maxRetryCount) {
      retryCarCheckout();
    } else {
      cy.log(`Maximum retry count reached. Checkout failed. Retried ${retryCount} times.`);
    }
  }

  static retryCarCheckout() {
    cy.get(rentalCarCheckout.seeMoreCars).eq(1).click();
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
  }

  static handleSuccessfulCheckout() {
    cy.log('Checkout successful');
  }

  static handleBookingResponse(Interception: Interception, saveBookingId?: boolean) {
    cy.task('putDataInCache', {
      key: 'rentalCarTripItemUuid',
      data: Interception.response?.body.tripId
    });

    Logs.cypressResponseLog('wait for booking', Interception);
    if (saveBookingId) {
      cy.task('putDataInCache', {
        key: 'rentalCarBookingId',
        data: Interception.response?.body.bookingUuid
      });
    }
  }

  static expectDirectBillError(xhr: Interception) {
    const responseBody = xhr.response?.body;
    const responseStatus = xhr.response?.statusCode;
    expect(responseStatus).to.eq(400);
    cy.log('Response body: ' + JSON.stringify(responseBody));
    expect(responseBody.errorType).to.eq('DATA_VALIDATION');
    expect(responseBody.message).to.eq(
      `Your loyalty information could not be applied. Please confirm that the account information is correct and try again.`
    );
  }
}
