import { Utility, utilitySelector, Timeouts } from '@utility-lib/index';

import {
  TrainTripType,
  TrainSearchResults,
  TrainSearch,
  tripItinerarySelectors
} from '@train-lib/index';

export const trainCheckoutSelector = {
  acknowledgment:
    '[class="train-checkout-summary__payment__terms-conditions__header"] [type="checkbox"]',
  bookTrain: '.train-checkout-summary__payment__button button',
  tripCheckout: '.ta-trip-checkout',
  loader: '[class^="loading-container"]',
  saveTripInfo: '[qaid="tripCheckoutCreateButton"]',
  bookingStatus: '.booking-success__left__title',
  tripInfoButton:
    '[qaid="trainCheckoutTripCheckout"] [class^="ta-trip-checkout__actions"]',
  homeSearch: '[class^="main-header__new-logo"] [href="/app/user2/search"]',
  renameTrip: '[formcontrolname="tripName"]',
  seatButton: '.train-seat .train-seat__content',
  ticketContainer: '.ticket__content',
  ticketContinue:
    '[class^="ticket__message-container rebranding"] button .ta-button__content',
  ticketTypeTitle: '[class^="ticket__option"] .ticket__option__title',
  seatPreferences: '.train-seat__content button',
  skipSeatMaps: '.seat-map-block__header__actions',
  trainSeat: '.train-seat__content',
  trainCheckoutPageSummary: '.checkout-card__content',
  totalBookingCharge: '.summary__total span:nth-child(2)',
  totalBookingChargeCurrency: '.charge-item__amount span',
  tripInvitationTitle: '.itinerary__content-body__invitation-label',
  bookingSuccessClose: '.booking-success__close__icon',
  toastMessage: '[class^="ta-toastr-event__message"]',
  summaryAmount: '[class="charge-item__right"] [class="charge-item__amount"]',
  chargeItemAmount: '.charge-item__amount',
  extras: '[class^="train-extras"] [type="checkbox"]',
  summaryItem: '[class^="train-checkout-summary__item"]',
  summaryAmountInDetail: '[class="charge-item__right"]',
  summaryTotal: '.summary__total',
  bahnCard: '[class="reminders__rows"] [class="reminders__highlight"]',
  trainImage: '[class="ta-trip-checkout__picture"]',
  summaryItemTitle: '[class="summary__item__title"]',
  disabledButton: '.train-checkout-summary__payment__button [disabled="true"]',
  checkedAck: '[class="ta-icon ta-checkbox__icon show"]',
  seatNumber: '[class="ta-tag ta-tag--size-small ta-tag--strong-black"]'
};
export class TrainCheckout {
  static setTripInfo() {
    cy.allure().logStep('set trip information');
    cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
    let maxRetries = 3;

    function clickSaveTripInfo() {
      cy.get(trainCheckoutSelector.saveTripInfo, Timeouts.MAX_TIMEOUT_120_SEC)
        .should('have.length.greaterThan', 0)
        .then(($btn) => {
          if ($btn.length > 0) {
            cy.get(trainCheckoutSelector.saveTripInfo)
              .contains(' Save trip info ')
              .click();
            cy.allure().logStep('add to this trip');
          } else {
            cy.allure().logStep('save trip information not required');
            if (maxRetries > 0) {
              maxRetries--;
              clickSaveTripInfo();
            }
          }
        });
    }

    clickSaveTripInfo();
  }

  static skipSeatMaps() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.bodySelector).then((body) => {
      const matchingElements = body.find(trainCheckoutSelector.skipSeatMaps);
      if (matchingElements.length > 0) {
        cy.allure().logStep('Seat maps were skipped');
        const elementsArray = matchingElements.toArray();

        elementsArray.forEach((element, index) => {
          cy.wrap(element).contains('Continue without selection').click({ force: true });

          if (index < elementsArray.length - 1) {
            cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
          }
        });
      } else {
        cy.allure().logStep('Seat maps not required');
      }
    });
  }

  static seatPreferences() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.bodySelector).then(($body) => {
      cy.allure().logStep('Seat Preferences continue without selection');
      if ($body.text().includes('Continue without selection')) {
        cy.contains('Continue without selection').click({ force: true });
      } else {
        cy.allure().logStep('Seat Preferences not found');
        cy.log('seat preference not found');
      }
    });
  }

  static renameTrip(tripName: string) {
    cy.wait('@waitForContract');
    cy.contains('Rename trip', Timeouts.MEDIUM_TIMEOUT_60_SEC).click();
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.clearInputAndType(trainCheckoutSelector.renameTrip, `${tripName}{enter}`);
    cy.allure().logStep('renameRoundTrips');
  }

  static selectTicketType(ticketTypeTitle: string) {
    cy.log('select ticket type if it finds');
    cy.get(utilitySelector.bodySelector).then((body) => {
      if (body.find(trainCheckoutSelector.ticketContinue).length > 0) {
        cy.get(trainCheckoutSelector.ticketTypeTitle).contains(`${ticketTypeTitle}`);
        cy.get(trainCheckoutSelector.ticketContinue).click();
        cy.allure().logStep(`${ticketTypeTitle} ticket selected`);
      } else {
        cy.allure().logStep('no ticket selection found');
      }
    });
  }

  static selectSeatPreference(preference: string) {
    cy.allure().logStep(`select ${preference}`);
    cy.get(utilitySelector.bodySelector).then((seatPreference) => {
      if (seatPreference.find(trainCheckoutSelector.trainSeat).length > 0) {
        cy.get(trainCheckoutSelector.seatButton).contains(`${preference}`).click();
        cy.allure().logStep('continue without selection');
      } else {
        cy.allure().logStep('no seat preference');
      }
    });
  }

  static setNewTripName() {
    cy.get(trainCheckoutSelector.tripCheckout, Timeouts.MEDIUM_TIMEOUT_60_SEC).should(
      'be.visible'
    );
    Utility.createNewTrip();
    Utility.saveTripInformation();
  }

  static acceptAcknowledgement() {
    cy.get(trainCheckoutSelector.acknowledgment).click({ force: true });
    cy.allure().logStep('acknowledgement accepted');
  }

  static bookTrain() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(trainCheckoutSelector.bookTrain).then(($button) => {
      cy.wrap($button).scrollIntoView();
      cy.wrap($button).should('be.visible');
      cy.wrap($button).click({ force: true });
      cy.allure().logStep('book train');
    });
  }

  static switchToNewLocationIfCheckoutFail() {
    //! let's check the stability of the test first.
    //! if the test fails then we can switch to new train search location
    //! and try again
    cy.get(utilitySelector.bodySelector).then((checkOutFail) => {
      if (checkOutFail.find(trainCheckoutSelector.toastMessage).length > 0) {
        cy.get(trainCheckoutSelector.homeSearch).eq(0).click();
        cy.allure().logStep('go back to train search page');
      }
    });
  }

  static expectBookingStatus(status: string) {
    cy.get(trainCheckoutSelector.bookingStatus, { timeout: 240000 }).contains(
      `${status}`
    );
    cy.allure().logStep(`booking status is ${status}`);
  }

  static confirmBooking() {
    cy.allure().logStep('Checking whether booking confirmed.');
    cy.get(tripItinerarySelectors.bookingConfirmationModal).should('be.visible');
    cy.get(tripItinerarySelectors.bookingConfirmationPopup)
      .find(tripItinerarySelectors.bookingConfirmationPopupCloseIcon)
      .click();
    cy.get(tripItinerarySelectors.bookingConfirmationModal).should('have.length', 0);
  }

  static confirmTripByInvitation() {
    cy.get(trainCheckoutSelector.tripInvitationTitle).should(
      'contain.text',
      'Trip by invitation'
    );
  }

  static swapToNewLocationsSNCF() {
    TrainSearch.visitTrainSearch('Business');
    TrainSearch.selectTripTileType(TrainTripType.ONEWAY);
    TrainSearch.setOrigin('Lille, FR');
    TrainSearch.setDestination('Nice, FR');
    TrainSearch.selectFutureTrainDate();

    TrainSearch.searchTrain();
    TrainSearchResults.expectSearchResultPresent();
    TrainSearchResults.expectProviderIsPresent('SNCF');
    TrainSearchResults.selectProvider('SNCF');
    TrainSearchResults.proceedToCheckoutPage();

    TrainCheckout.renameTrip('One-Way Trip SNCF');
    TrainCheckout.setTripInfo();
    TrainCheckout.selectSeatPreference(' Continue without selection ');
    TrainCheckout.acceptAcknowledgement();
    TrainCheckout.bookTrain();
    TrainCheckout.expectBookingStatus('Train booking confirmed!');
  }

  static expectBookingStatusSNCF(status: string) {
    cy.get(utilitySelector.bodySelector).then((body) => {
      if (body.find(trainCheckoutSelector.bookingStatus).length > 0) {
        cy.get(
          trainCheckoutSelector.bookingStatus,
          Timeouts.MAX_TIMEOUT_120_SEC
        ).contains(`${status}`);
        cy.allure().logStep(`booking status is ${status}`);
      } else {
        cy.allure().logStep('Booking failed');
        cy.contains(' Edit search ').click();
        TrainCheckout.swapToNewLocationsSNCF();
      }
    });
  }

  static storeBookingData() {
    cy.get(trainCheckoutSelector.totalBookingCharge).then((element) => {
      cy.task('putDataInCache', {
        key: 'trainTotalBookingCharge',
        data: element.text().trim()
      });
    });

    cy.get(trainCheckoutSelector.totalBookingChargeCurrency)
      //.eq(1)
      .then((element) => {
        cy.task('putDataInCache', {
          key: 'trainTotalBookingChargeCurrency',
          data: element.text().trim()
        });
      });
  }

  static checkTripFeeInCheckoutPageSummary(fee: string) {
    cy.get(trainCheckoutSelector.trainCheckoutPageSummary)
      .should('contain', fee)
      .should('be.exist');
  }

  static BookingSuccessModelClose() {
    cy.get(trainCheckoutSelector.bookingSuccessClose).click();
  }

  static getTotalSummaryAmount() {
    cy.get(trainCheckoutSelector.summaryAmount)
      .eq(2)
      .invoke('text')
      .then((text) => {
        const numericPart = text.match(/[\d.]+/) || ['0'];
        const subTotalAmount = parseFloat(numericPart[0]);
        cy.log('Sub total amount: ' + subTotalAmount);
        cy.task('putDataInCache', {
          key: 'trainTicketSubTotalAmount',
          data: subTotalAmount
        });
      });

    cy.get(trainCheckoutSelector.chargeItemAmount)
      .invoke('text')
      .then((text) => {
        const amount = parseFloat(text.replace(/[^\d.,]/g, '').replace(',', '.'));
        const totalAmountWithoutSeat = amount.toFixed(2);

        cy.log(`Extracted amount: ${totalAmountWithoutSeat}`);
        cy.task('putDataInCache', {
          key: 'totalAmountWithoutSeat',
          data: totalAmountWithoutSeat
        });
      });
  }

  static selectDbSeat() {
    cy.get(trainCheckoutSelector.extras).should('be.visible');
    cy.get('[class="ta-toggle toggle-size-regular"]')
      .should('be.visible')
      .then(($elements) => {
        // Click all available seats
        $elements.each((index) => {
          cy.get('[class="ta-toggle toggle-size-regular"]').eq(index).click();
          cy.wait('@waitForSeatAdded');
        });
      });
  }

  static expectSeatReservationAddedInSummaryOfCharges() {
    cy.get(trainCheckoutSelector.summaryAmount).should(
      'contain.text',
      'Seat reservation '
    );
    cy.get(trainCheckoutSelector.summaryAmountInDetail)
      .eq(1)
      .invoke('text')
      .then((text) => {
        const numericPart = text.match(/[\d.,]+/) || ['0'];
        const chargeAmount = parseFloat(numericPart[0].replace(/,/g, ''));
        cy.log('Sub total amount :' + chargeAmount);
        cy.task('putDataInCache', {
          key: 'seatReservationPrice',
          data: chargeAmount
        });
      });
  }

  static expectBahnCardPresentInCheckout(bahnCardType: string, loyaltyCard = false) {
    if (loyaltyCard === true) {
      cy.get(trainCheckoutSelector.bahnCard).should('be.visible');
      cy.get(trainCheckoutSelector.bahnCard).should('contain.text', bahnCardType);
    }
  }
  static expectNoOfTravelers(noOfTravelers: number) {
    cy.get(trainCheckoutSelector.summaryItemTitle)
      .eq(0)
      .should('contain.text', noOfTravelers);
    cy.allure().logStep(`expect ${noOfTravelers} travelers`);
  }

  static expectSeatNumberIsPresent() {
    cy.get(trainCheckoutSelector.seatNumber)
      .invoke('text')
      .then((seatNumberFoundInCheckout) => {
        cy.log('Seat number found:', seatNumberFoundInCheckout);

        cy.task('getDataFromCache', 'seatNumberFound').then((seatNumber: any) => {
          cy.log('seat Number Found:  ======::::>>>>', seatNumber);
          expect(seatNumber).to.equal(seatNumber);
        });
      });
  }
}
