import {
  Logs,
  guidRegex,
  Utility,
  utilitySelector,
  Timeouts,
  InputDelays
} from '@utility-lib/index';
import { AmplitudeEvents } from '@growth-lib/amplitude-events';
import { Interception } from 'cypress/types/net-stubbing';
import { FlightBookingParams } from '@flight-modal/flight_booking_utility';
import { FlightTripType } from './search';

const flightCheckoutSelector = {
  saveButton: '.ta-button__content',
  changeCancellationPolicy: '.ta-checkout-booking-policy__continue span',
  contactDetailsContinueButton: '.flight-checkout__contact .ta-button__content',
  travelerCheckIn: '.ta-checkout-traveler button',
  bookFLight: ' [qaid="flightContractBook"]',
  cancellationTitle: '[title="Change, cancelation, and refund policy"]',
  continueCancellation: '.ta-checkout-booking-policy .ta-button__content',
  skipCheckIn: '[class^="ta-checkout-traveler__ancillaries_action__skip ta-button"]',
  flightBookedStatusTitle: '.booking-success__left__title',
  passportInfo: '[title="Passport & visa information"]',
  passportAcknowLedgement:
    '[qaid="passportAndVisaCheckoutCard"] .mat-checkbox-inner-container',
  setPassPortInfo: '[qaid="passportAndVisaCheckoutCard"] .ta-button__content',
  bookingSuccessMsg: '[qaid="flightConfirmed"]',
  roundTripInfo: '[qaid="tripCheckoutShowAllTripsBlock"] [qaid="tripNameInputDiv"]',
  addTripInfo: '.ta-trip-checkout__select .ta-button__content',
  bundledFlightSuccessMsg: '.booking-success .booking-success__left__title',
  bookingSummary: '.booking-item',
  outOfPolicyHeader: 'ta-out-of-policy',
  outOfPolicyHeaderGuest: '[headerprimarybuttonlabel="Your policy"]',
  outOfPolicyBookingReason: 'textarea[formcontrolname="reason"]',
  acceptOOPAcknowledgement: 'ta-out-of-policy .mat-checkbox-inner-container',
  acceptOOPAcknowledgementGuest:
    '[headerprimarybuttonlabel="Your policy"] .mat-checkbox-inner-container',
  continueOOPFlight: 'ta-out-of-policy [qaid="infoBannerPrimaryButton"]',
  continueOOPFlightGuest:
    '[headerprimarybuttonlabel="Your policy"] [qaid="infoBannerPrimaryButton"]',
  requireDataSection: '.checkout-card .traveler-require-data__form',
  requireDataEmail: 'input[formcontrolname="alternateEmail"]',
  requireDataSave: '[data-testid="traveler-required-save"]',
  numberOfTravelers:
    '.flight-checkout-booking-summary__in-booking > :nth-child(1) > :nth-child(2) > span',
  bookFlightPopup: 'div.booking-success__close ta-svg-image div',
  viewTrips: '.booking-complete-others__left__buttons > :nth-child(2) > div',
  flightBookingTotalCharges:
    '.flight-checkout-booking-summary__est-total div span:nth-child(1)',
  flightBookingTotalCurrency:
    '.flight-checkout-booking-summary__est-total div span:nth-child(2)',
  promoCardPercentage: '.ta-promotion-rebate-dropdown span',
  oopFlightHeader: '[titletype="WARNING"] .policy-slash',
  oopReasonHeader:
    '[qaid="outOfPolicyCheckoutCard"] [class="booking-policy booking-policy__oop"]',
  acceptOOPReasonAcknowledgement:
    '[qaid="outOfPolicyCheckoutCard"] .mat-checkbox-inner-container',
  continueOOPReasonFlight:
    '[qaid="outOfPolicyCheckoutCard"][qaid="infoBannerPrimaryButton"]',
  creditCardNumber: '[class^="ta-payment-card--digits"]',
  confirmationModalNotEmployeeBook: 'ta-information-modal .ta-button__content',
  confirmButtonNotEmployeeBook: 'ta-information-modal .ta-button__content',
  loyaltyCardInfo: '.ta-guest-info-loyalty-card__details',
  securePriceModal: '.ta-exit-secure-price-modal',
  securePriceModalCTAApprove: '.ta-modal-footer__main-block .ta-button--primary-theme',
  checkoutInsuranceLocation: '[data-testid="ta-insurance-addressLine1"]',
  checkoutInsuranceFirstName: '[data-testid="ta-insurance-firstName"]',
  checkoutInsuranceLastName: '[data-testid="ta-insurance-lastName"]',
  checkoutInsuranceEmail: '[data-testid="ta-insurance-email"]',
  checkoutInsuranceRelation: '[data-testid="ta-insurance-relation"]',
  autoCompleteLocationsItems: '.ta-location-search-v2__item',
  checkoutInsuranceRelationItems: '.ta-select-option',
  checkoutInsuranceContinue: '[data-testid="ta-insurance-continue"]',
  tripFeeCheckOut: 'div.checkout-card__content ta-charge-item',
  tripFeeValue: 'div.charge-item__right-top',
  checkoutGuestInfo: '.checkout-card__content ta-guest-info-v2',
  tripInfoSection: 'ta-trip-checkout-v2 .ta-trip-checkout',
  flightContractLegBlock: '[qaid="flightContractLegBlock"]',
  flightCardMiniDepartureAirport: '[qaid="flightCardMiniDepartureAirport"]',
  flightCardMiniArrivalAirport: '[qaid="flightCardMiniArrivalAirport"]',
  skipSeatSelection: '[qaid="checkoutTravelerSkipAncillaries"]',
  infoBannerCheckbox: '.info-banner__checkbox'
};

export class FlightCheckout {
  static waitToPageBeLoaded(): void {
    cy.allure().logStep('wait for flight checkout page loaded');
    FlightCheckout.verifyUrlAndTripInfoSection();
    cy.wait(['@waitForMatchingTrips', '@waitForPaymentMethods']);
  }

  static verifyUrlAndTripInfoSection() {
    cy.url().should(
      'match',
      new RegExp(
        `/search/(flights|flightBundles|flightBundlesFlex|)/${guidRegex}/contracts/${guidRegex}`
      )
    );
    cy.get(flightCheckoutSelector.tripInfoSection).should('be.visible');
  }

  static setTripInfo() {
    Utility.saveTripInformation();
  }

  static isCurrentUrlCheckoutPage(): Cypress.Chainable<boolean> {
    const regExValue = `\\/search\\/flights\\/${guidRegex}\\/contracts\\/${guidRegex}`;
    return cy
      .location('pathname', Timeouts.MEDIUM_TIMEOUT_60_SEC)
      .then((pathName) => !!pathName.match(regExValue));
  }

  static saveTripInformation() {
    Utility.saveTripInformation();
  }

  static createTripInformation() {
    Utility.createNewTrip();
    cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
    Utility.saveTripInformation();
  }

  static updateContactDetails() {
    cy.allure().logStep('continue contact details');
    cy.get(flightCheckoutSelector.infoBannerCheckbox).eq(0).click();
    cy.get(flightCheckoutSelector.contactDetailsContinueButton).click();
  }

  static changeCancellationPolicy() {
    cy.allure().logStep('continue contact details');
    cy.get(flightCheckoutSelector.changeCancellationPolicy).click();
  }

  static updateEmailDetails(email: string) {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.log('log personal email details');
    cy.get(utilitySelector.bodySelector).then(($body) => {
      if ($body.find(flightCheckoutSelector.requireDataSection).length > 0) {
        cy.allure().logStep('enter required email details');
        cy.log('enter required email details');
        cy.get(flightCheckoutSelector.requireDataEmail).type(
          email,
          InputDelays.INPUT_DELAY_100_MILLIS
        );
        cy.get(flightCheckoutSelector.requireDataSave).click();
      } else {
        cy.log('enter required email details not required');
      }
    });
  }

  static checkIn(checkInType?: string) {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.bodySelector).then(($body) => {
      if (checkInType && $body.text().includes(`${checkInType}`)) {
        cy.get(flightCheckoutSelector.travelerCheckIn).contains(`${checkInType}`).click();
        cy.allure().logStep('add check in');
      } else {
        cy.allure().logStep('skip check in');
        cy.get(flightCheckoutSelector.skipCheckIn, Timeouts.SHORT_TIMEOUT_3_SEC).each(
          (ele) => {
            cy.wrap(ele).click();
          }
        );
      }
    });
  }

  static checkInSeveralForPassengers(numberOfPassengers: number, checkInType?: string) {
    Cypress._.times(numberOfPassengers, () => {
      FlightCheckout.checkIn(checkInType);
    });
  }

  static storeBookingData() {
    cy.get(flightCheckoutSelector.flightBookingTotalCharges).then((element) => {
      cy.task('putDataInCache', {
        key: 'flightBookingTotalCharges',
        data: element.text().trim()
      });
    });
    cy.get(flightCheckoutSelector.flightBookingTotalCurrency).then((element) => {
      cy.task('putDataInCache', {
        key: 'flightBookingTotalChargesCurrency',
        data: element.text().trim()
      });
    });
    if (
      Cypress.$(`${flightCheckoutSelector.tripFeeCheckOut}:contains('Trip fee')`).length >
      0
    ) {
      cy.contains(flightCheckoutSelector.tripFeeCheckOut, 'Trip fee')
        .find(flightCheckoutSelector.tripFeeValue)
        .should('exist')
        .then((value) => {
          cy.task('putDataInCache', {
            key: 'tripFeeCheckOut',
            data: value.text().trim()
          });
        });
    }
  }

  static bookAndPay(flightParams: FlightBookingParams): void {
    if (flightParams.isExchangeFlow) {
      cy.intercept('POST', '**/api/v1/trip/flight/exchange/book/**/contract/**').as(
        'waitForFlightBooking'
      );
    } else if (
      flightParams.flightTripType === FlightTripType.ONEWAY ||
      flightParams.flightTripType === FlightTripType.ROUNDTRIP
    ) {
      cy.intercept(
        'POST',
        '**/api/v1/trip/flight/searches/**/contracts/**/book/streaming**'
      ).as('waitForFlightBooking');
    } else if (flightParams.flightTripType === FlightTripType.MULTICITY_BUNDLE) {
      cy.intercept(
        'POST',
        '**/api/v1/trip/flight/bundle/searches/**/contracts/**/book**'
      ).as('waitForFlightBooking');
    } else if (flightParams.flightTripType === FlightTripType.MULTICITY_CUSTOM) {
      cy.intercept(
        'POST',
        '**/api/v1/trip/flight/bundle/flexible/searches/**/contracts/**/book**'
      ).as('waitForFlightBooking');
    }

    cy.get(flightCheckoutSelector.bookFLight).click();
    this.confirmBookForNotCompanyEmployee();
    cy.wait('@waitForFlightBooking').then((xhr) => {
      this.setToCacheSuggestedHotelSearch(xhr);
      Logs.cypressRequestLog('FLIGHT CHECKOUT RESPONSE', xhr);
    });

    cy.allure().logStep('Book a flight');
    cy.get(utilitySelector.bodySelector).then((body) => {
      if (body.find(flightCheckoutSelector.bookFlightPopup).length > 0) {
        cy.get(flightCheckoutSelector.bookFlightPopup).click();
      }
    });
  }

  static confirmBookForNotCompanyEmployee() {
    cy.get(utilitySelector.bodySelector).then((body) => {
      if (body.find(flightCheckoutSelector.confirmationModalNotEmployeeBook).length > 0) {
        cy.get(flightCheckoutSelector.confirmButtonNotEmployeeBook)
          .contains('Confirm')
          .click();
      }
    });
  }

  static confirmDropSecureModal(): void {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.bodySelector).then((body) => {
      if (body.find(flightCheckoutSelector.securePriceModal).length > 0) {
        cy.get(flightCheckoutSelector.securePriceModalCTAApprove)
          .contains('Back to checkout')
          .click();
        AmplitudeEvents.addExpectedAmplitudeEvents(
          'Checkout drop pop up showed',
          'Checkout drop pop up clicked'
        );
      }
    });
  }

  static isSecuredModalRemoved(): void {
    cy.get(utilitySelector.bodySelector).then((body) => {
      expect(body.find(flightCheckoutSelector.securePriceModal).length).to.equal(0);
    });
  }

  private static setToCacheSuggestedHotelSearch(xhr: Interception): void {
    cy.task('putDataInCache', {
      key: 'suggestedHotelSearch',
      data: !!xhr.response?.body?.suggestedHotelSearch
    });
  }

  static checkCancellationPolicy() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.log(' check Cancellation Policy');
    cy.get(utilitySelector.bodySelector).then((cancellation) => {
      if (cancellation.find(flightCheckoutSelector.changeCancellationPolicy).length) {
        cy.get(flightCheckoutSelector.changeCancellationPolicy).click();
        cy.allure().logStep('continue cancellation policy ');
      } else {
        cy.allure().logStep('Cancellation refund not found');
        cy.log('Cancellation refund not found');
      }
    });
  }

  static acceptOutOfPolicyFlight() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.log('add oop reason ');
    cy.get(utilitySelector.bodySelector).then((outOfPolicy) => {
      if (outOfPolicy.find(flightCheckoutSelector.oopFlightHeader).length > 0) {
        cy.get(flightCheckoutSelector.outOfPolicyBookingReason).type(
          'Urgent booking required'
        );
        cy.get(flightCheckoutSelector.acceptOOPAcknowledgement).click();
        cy.get(flightCheckoutSelector.continueOOPFlight).click();
        cy.allure().logStep('accept out of policy');
      } else {
        cy.allure().logStep('out of policy not found');
        cy.log('out of policy not found');
      }
    });
  }
  static acceptOopAndMentionReason() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.log('add oop reason ');
    cy.get(utilitySelector.bodySelector).then((outOfPolicy) => {
      if (outOfPolicy.find(flightCheckoutSelector.oopReasonHeader).length > 0) {
        cy.get(flightCheckoutSelector.outOfPolicyBookingReason).type(
          'Urgent booking required'
        );
        cy.get(flightCheckoutSelector.acceptOOPReasonAcknowledgement).click();
        cy.get(flightCheckoutSelector.continueOOPReasonFlight).last().click();
        cy.allure().logStep('accept out of policy');
      } else {
        cy.allure().logStep('out of policy not found');
        cy.log('out of policy not found');
      }
    });
  }
  // delete when Guest flow UI updated to the latest version
  static acceptOutOfPolicyFlightGuestFlow() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.bodySelector).then((outOfPolicy) => {
      if (outOfPolicy.find(flightCheckoutSelector.outOfPolicyHeaderGuest).length > 0) {
        cy.get(flightCheckoutSelector.outOfPolicyBookingReason).type(
          'Urgent booking required'
        );
        cy.get(flightCheckoutSelector.acceptOOPAcknowledgementGuest).click();
        cy.get(flightCheckoutSelector.continueOOPFlightGuest)
          .contains(' Continue ')
          .click();
        cy.allure().logStep('accept out of policy');
      } else {
        cy.allure().logStep('out of policy not found');
        cy.log('out of policy not found');
      }
    });
  }

  static validateIfPassportAndVisaInfoRequired() {
    cy.get(utilitySelector.bodySelector).then((passport) => {
      if (passport.find(flightCheckoutSelector.passportAcknowLedgement).length > 0) {
        cy.get(flightCheckoutSelector.passportAcknowLedgement).click();
        cy.get(flightCheckoutSelector.setPassPortInfo).click();
        cy.allure().logStep('add passport detail');
      } else {
        cy.allure().logStep('passport detail not required');
        cy.log('Passport not required');
      }
    });
  }

  static expectBookingSummary(tripName: string) {
    cy.get(flightCheckoutSelector.bookingSummary).contains(`${tripName}`);
    cy.allure().logStep(`${tripName} is present`);
  }

  static expectFlightSuccessfullyConfirmed(successMsg: string) {
    cy.get(flightCheckoutSelector.bookingSuccessMsg, Timeouts.MAX_TIMEOUT_120_SEC).should(
      'be.contain',
      `${successMsg}`
    );
    cy.allure().logStep('Flight is successfully booked');
  }

  static expectBundledFlightSuccessfullyBooked(successMsg: string) {
    cy.get(
      flightCheckoutSelector.bundledFlightSuccessMsg,
      Timeouts.MAX_TIMEOUT_120_SEC
    ).should('be.contain', `${successMsg}`);
    cy.allure().logStep('Flight is successfully booked');
  }

  static expectNumberOfTravelers(numberOfTravelers: number): void {
    cy.get(flightCheckoutSelector.numberOfTravelers).should(
      'contain.text',
      numberOfTravelers
    );
  }

  static viewTrips() {
    cy.get(flightCheckoutSelector.viewTrips).click();
  }

  static verifyPromoCard(value: string) {
    cy.get(flightCheckoutSelector.promoCardPercentage).should(
      'contain.text',
      `${value} gift card earned`
    );
  }

  static storeCreditCardLastDigits() {
    cy.get(flightCheckoutSelector.creditCardNumber)
      .eq(0)
      .invoke('text')
      .then((text) => {
        const cardNumber = text.replace(/[^0-9 ]/g, '');
        cy.task('putDataInCache', {
          key: 'cardNumber',
          data: cardNumber
        });
      });
  }

  static verifyLoyaltyCardInfo(loyaltyCardInfo: string) {
    cy.allure().logStep('verify loyalty card info');
    cy.get(flightCheckoutSelector.loyaltyCardInfo).contains(loyaltyCardInfo);
  }

  static addInsurance() {
    cy.allure().logStep('add insurance');
    cy.get(flightCheckoutSelector.checkoutInsuranceLocation).type(
      'NEVERLAND TOKYO, 2 Chome-21-7 Dogenzaka, Shibuya City, Tokyo, Japan'
    );
    cy.get(flightCheckoutSelector.autoCompleteLocationsItems).first().trigger('click', {
      force: true
    });
    cy.get(flightCheckoutSelector.checkoutInsuranceRelation).click();
    cy.get(flightCheckoutSelector.checkoutInsuranceRelationItems)
      .first()
      .trigger('click', {
        force: true
      });
    cy.get(flightCheckoutSelector.checkoutInsuranceFirstName).type('Eevee');
    cy.get(flightCheckoutSelector.checkoutInsuranceLastName).type('Pikachu');
    cy.get(flightCheckoutSelector.checkoutInsuranceEmail).type('pokemon@world.com');
    cy.get(flightCheckoutSelector.checkoutInsuranceContinue).click();
  }

  static verifyNumberOfTravelers(travelersNumber: number) {
    cy.allure().logStep(`verify number of travelers is equeal to ${travelersNumber}`);
    cy.get(flightCheckoutSelector.checkoutGuestInfo).should(
      'have.length',
      travelersNumber
    );
  }

  static verifyFlightLocation(flightBookingParams: FlightBookingParams) {
    const checkAirports = (index: number, departure: string, arrival: string) => {
      cy.get(flightCheckoutSelector.flightContractLegBlock)
        .eq(index)
        .as('flightBlock')
        .then(() => {
          cy.get('@flightBlock')
            .find(flightCheckoutSelector.flightCardMiniDepartureAirport)
            .should('contain.text', departure);

          cy.get('@flightBlock')
            .find(flightCheckoutSelector.flightCardMiniArrivalAirport)
            .should('contain.text', arrival);
        });
    };
    if (flightBookingParams.flightTripType === 'ROUNDTRIP') {
      const departure = flightBookingParams.locations[0].slice(0, 3);
      const arrival = flightBookingParams.locations[1].slice(0, 3);
      checkAirports(0, departure, arrival);
      checkAirports(1, arrival, departure);
    }
  }

  static skipSeatSelection() {
    cy.get(utilitySelector.bodySelector).then((body) => {
      if (body.find(flightCheckoutSelector.skipSeatSelection).length > 0) {
        cy.get(
          flightCheckoutSelector.skipSeatSelection,
          Timeouts.SHORT_TIMEOUT_3_SEC
        ).each((ele) => {
          cy.wrap(ele).click();
        });
        cy.allure().logStep('Seat maps were skipped');
      } else {
        cy.allure().logStep('Seat maps not required');
      }
    });
  }
}
