import { guidRegex, TripTileType, utilitySelector, Timeouts, Utility } from '@utility-lib/index';
import { TrainCancellation, TrainTripType, trainCheckoutSelector } from '@train-lib/index';
import { FlightItinerary } from '@flight-lib/itinerary';
import { Invoice } from '@commerce-lib/invoice/invoice';
import { InvoiceValidation } from '@commerce-lib/trains/invoice_validations';
import { CommerceShared } from '@commerce-lib/shared';
const adminCreds = Cypress.env('newUser').NEW_USER_PASSWORD;

export const tripItinerarySelectors = {
  bookingConfirmationModal: '.booking-success',
  bookingConfirmationPopup: '[qaid="bookingSuccessClose"]',
  bookingConfirmationPopupCloseIcon: '.booking-success__close__icon',
  cancelTicket: '[qa-id="event-action-cancel-train"]',
  segmentCheckbox: '["class = mat-checkbox-inner-container"]',
  bookingSummarySection: '.train-booking-details',
  totalBookingChargeOnItinerary: '.train-booking-details',
  cancelUnavailable: '[class="action--cancel-v2--blue action--disabled"]',
  tripType: 'navan-trip-type-tag',
  exchangeTicket: '.action--change-v2',
  tripBookingId: '.train-booking-details__row__value',
  issuerName: 'div.segment__info__operator span:first-child',
  location: '.segment__route-info__station:last-child',
  seatDetails: '[class^="ta-train-passenger-details__info__title"]',
  segments: '[class="trip-timeline__booking-title"] [qaid="itineraryListRailSegment"]',
  passengers: '[class="ta-train-passenger-details__passenger"]',
  transferInfo: '[class="transfer-info"]',
  passengerDetailedInfo: '[class^="ta-train-passenger-details__info__title"]',
  passengerDetail: '[data-testid="trainPassengerDetails"]',
  checkInInfo: '[class="check-in-info__content"]',
  checkInButton: '[data-testid="checkInInfoBannerCheckInButton"]',
  seatNumber: '[data-testid="trainPassengerDetailsSeatNumber"]',
  departureDateInfo: '[data-testid="segmentDetailsDepartureDate"]',
  bookingTitle: '[class="trip-timeline__booking-title"]',
  operatorLogo: '[data-testid="segmentDetailsOperatorLogo"][src*=".png"]',
  eTicket: '[qa-id="event-action-download-eticket-rail"]',
  ETicketDisabled: '[class^="trip-manage-panel__ticket-button ta-button ta-button--disabled"]',
  eventActionDownloadETicketRail: '[qaid="eventActionDownloadEticketRail"] span'
};

export class TrainItinerary {
  static openTripItinerary() {
    cy.allure().logStep('open itinerary');
    cy.get(tripItinerarySelectors.bookingConfirmationPopup)
      .find(tripItinerarySelectors.bookingConfirmationPopupCloseIcon)
      .click();
    cy.allure().logStep('itinerary opened');
    cy.wait('@waitForTripTimeline');
    this.expectOperatorIconIsPresent();
  }

  //to remove the cy.wait() after fixing this issue https://navancorp.atlassian.net/browse/TRAIN-5957
  static reloadItinerary() {
    cy.wait(Timeouts.MAX_TIMEOUT_120_SEC.timeout);
    cy.reload();
  }
  static goToItineraryPage() {
    cy.task('getDataFromCache', 'TrainItineraryURL').then((goToItineraryURL: any) => {
      cy.visit(goToItineraryURL);
      cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    });
  }

  static clickCancelTicket() {
    this.cancelTicket();
    cy.wait('@waitForBookingStatusUpdate');
    cy.allure().logStep('cancel trip button clicked');
  }

  static waitUntilItineraryLoaded() {
    cy.allure().logStep('wait until itinerary page is loaded');
    cy.url().should('match', RegExp(`/app/user2/trips/${guidRegex}/itinerary`));
    cy.wait('@waitForTripTimeline');
  }

  static cancelTicket() {
    cy.get(utilitySelector.bodySelector).then((btn) => {
      if (btn.find(tripItinerarySelectors.cancelUnavailable).length > 0) {
        cy.wait(Timeouts.MEDIUM_TIMEOUT_60_SEC.timeout);
        cy.reload();
        cy.get(tripItinerarySelectors.cancelTicket).click();
      } else {
        cy.get(tripItinerarySelectors.cancelTicket).click();
      }
    });
  }

  static checkTripFeeOnItinerarySummarySection(fee: string) {
    cy.get(tripItinerarySelectors.bookingSummarySection).then((button) => {
      cy.wrap(button).should('be.visible').scrollIntoView({ duration: 100 });
      cy.wrap(button).should('contain', fee).should('exist');
    });
  }

  static checkBookingTotalPriceOnItineraryPage() {
    cy.allure().logStep(` Check Booking Total Price :`);
    cy.task('getDataFromCache', 'trainTotalBookingCharge').then((totalBookingCharge) => {
      cy.get(tripItinerarySelectors.totalBookingChargeOnItinerary).should(($el) => {
        const text = $el.text().trim().replace(/\s+/g, ' ');
        expect(text).contains(totalBookingCharge);
      });
    });
  }

  static verifyTripTile(tripTile: TripTileType) {
    cy.allure().logStep(`verify tripType should be ${tripTile}`);
    cy.get(tripItinerarySelectors.tripType).contains(tripTile);
  }

  static cancelTrip() {
    this.cancelTicket();
    TrainCancellation.roundSegmentsSelectionCancellation();
    TrainCancellation.cancellationCheckout();
  }

  static exchangeTicket() {
    cy.get(tripItinerarySelectors.exchangeTicket, Timeouts.MAX_TIMEOUT_120_SEC).contains('Exchange ticket').click();
    cy.wait('@waitForBookingStatusUpdate');
    cy.allure().logStep('change trip button clicked');
  }

  static waitToBeLoaded(): void {
    const putDataInCache = (key: string, selector: string, index = 0) => {
      cy.get(selector)
        .eq(index)
        .then((element) => {
          cy.task('putDataInCache', {
            key: key,
            data: element.text().trim()
          });
        });
    };

    putDataInCache('bookingID', tripItinerarySelectors.tripBookingId, 1);
    cy.url().then((url) => {
      cy.log('<<< Train Itinerary URL is >>>: ' + url);
      cy.task('putDataInCache', {
        key: 'TrainItineraryURL',
        data: url
      });
    });
    putDataInCache('issuerName', tripItinerarySelectors.issuerName);
    putDataInCache('departureLocation', tripItinerarySelectors.location, 0);
    putDataInCache('arrivalLocation', tripItinerarySelectors.location, 1);

    cy.wait('@invoice').then((interception) => {
      cy.task('putDataInCache', {
        key: 'bookingUuid',
        data: interception.request.url.split('/')[7]
      });
    });
  }

  static verifyUnchangeableInvoice() {
    cy.wait(Timeouts.MEDIUM_TIMEOUT_60_SEC.timeout);
    FlightItinerary.forcePDFSyncAPI();
    Utility.loginAsAdmin(adminCreds);
    TrainItinerary.goToItineraryPage();
    InvoiceValidation.storeTrainItineraryTripData();
    CommerceShared.visitViewInvoicePage();
    Invoice.retrieveDownloadInvoiceFile();
    Invoice.retrieveAndConvertPDFInvoiceDetailsToHTML();
    InvoiceValidation.checkBookingId();
    InvoiceValidation.totalTrainAmountValidation();
    InvoiceValidation.checkTrainUnchangeabilityData();
  }

  static expectDBSeatDetailIsPresent() {
    cy.log('<<< DB seat details are present >>>');
    cy.allure().logStep('DB seat details are present');
    cy.task('getDataFromCache', 'noOfSegments').then((noOfSeat: any) => {
      cy.get(tripItinerarySelectors.passengerDetail).should('have.length', noOfSeat + 1);
    });
    cy.get(tripItinerarySelectors.passengerDetail).each((coachElement) => {
      cy.wrap(coachElement)
        .find(tripItinerarySelectors.passengerDetailedInfo)
        .should('contain', ' Coach ')
        .and('contain', ' Seat ');
    });
  }

  static expectSeatDetailsArePresent() {
    cy.get(tripItinerarySelectors.passengerDetail).each((coachElement) => {
      cy.wrap(coachElement)
        .find(tripItinerarySelectors.passengerDetailedInfo)
        .should('contain', ' Coach ')
        .and('contain', ' Seat ');
    });
  }

  static expectCoachAndSeatDetailsArePresent() {
    cy.get(tripItinerarySelectors.seatDetails).should('contain', ' Coach ').and('contain', ' Seat ');
    cy.allure().logStep('Expect coach and seat details are present');
  }

  static expectNoOfSeatsAndCoachesPresent(noOfTravellers: number) {
    this.expectNoOfTravelerPresent(noOfTravellers);
    cy.get(tripItinerarySelectors.passengerDetail).each((coachElement) => {
      cy.wrap(coachElement)
        .find(tripItinerarySelectors.passengerDetailedInfo)
        .should('contain', ' Coach ')
        .and('contain', ' Seat ');
    });
  }

  static expectNoOfTravelerPresent(noOfTravellers: number) {
    cy.get(tripItinerarySelectors.passengers).should('have.length', noOfTravellers);
    cy.allure().logStep('No of travellers are present');
  }

  static expectRoundTripSeatDetailsArePresent(noOfTraveler: number) {
    cy.get(tripItinerarySelectors.segments).last().click();
    this.expectNoOfSeatsAndCoachesPresent(noOfTraveler);
    TrainItinerary.expectSeatDetailsArePresent();
    cy.allure().logStep('Round trip seat details are present');
  }

  static expectNoOfSegmentsArePresent() {
    cy.task('getDataFromCache', 'noOfSegmentsFromSearchResults').then((text: any) => {
      cy.get(tripItinerarySelectors.transferInfo).should('have.length', text);
    });
  }

  static expectNoOfSegmentAndSeatDetailIsEqual() {
    cy.wait('@invoice');
    cy.get(tripItinerarySelectors.passengers).then(($elements) => {
      const coachElements = $elements.filter(':contains("Coach")');
      const coachElementsLength = coachElements.length;
      cy.log(JSON.stringify(coachElementsLength));
      expect($elements.length).to.equal(coachElementsLength);
    });
    cy.allure().logStep('Expect no of segment and seat details are present');
  }

  static expectLoyaltyCardDetailsArePresent(loyaltyCard: string) {
    cy.get(trainCheckoutSelector.bahnCard).should('be.visible').should('contain', loyaltyCard);
    cy.allure().logStep('Expect loyalty card details are present');
  }

  static expectCheckInDetailsArePresent() {
    cy.get(tripItinerarySelectors.checkInInfo).should('be.visible');
    cy.get(tripItinerarySelectors.checkInButton).should('be.visible');
    cy.allure().logStep('Expect check in details are present');
  }

  static expectCheckInDetailsAreNotPresent() {
    cy.get(tripItinerarySelectors.checkInInfo).should('not.exist');
    cy.get(tripItinerarySelectors.checkInButton).should('not.exist');
    cy.allure().logStep('Expect check in details are not present');
  }
  static expectMultiSegmentTransferInfoIsPresent() {
    cy.get('[class="transfer-info"] ').should('contain', 'transfer time');
  }

  static expectSeatMapDetailsArePresent(tripType: TrainTripType, roundTripLeg = 1) {
    const getSeatNumberFromItinerary = () => {
      cy.get(tripItinerarySelectors.seatNumber).last().invoke('text').as('seatNumberFoundOnItinerary');
    };

    const compareSeatNumbers = (cacheKey: string) => {
      cy.get('@seatNumberFoundOnItinerary').then((seatNumberFoundOnItinerary) => {
        cy.task('getDataFromCache', cacheKey).then((seatNumber) => {
          cy.log('Seat number found:', seatNumberFoundOnItinerary);
          cy.log('Seat number from cache:', seatNumber);
          expect(seatNumberFoundOnItinerary).to.equal(seatNumber);
        });
      });
    };

    if (tripType === TrainTripType.ONEWAY) {
      getSeatNumberFromItinerary();
      compareSeatNumbers('seatNumberFound');
    } else if (tripType === TrainTripType.ROUND_TRIP) {
      // Departure leg
      getSeatNumberFromItinerary();
      compareSeatNumbers(`seatNumberRoundTrip_${roundTripLeg}`);
      // Wait and navigate to the return leg
      cy.get(tripItinerarySelectors.bookingTitle).last().click({ force: true });
      cy.get(tripItinerarySelectors.segments).last().click();
      cy.wait(Timeouts.SHORT_TIMEOUT_2_SEC.timeout);
      // Arrival leg
      getSeatNumberFromItinerary();
      cy.log('Round trip leg:', roundTripLeg + 1);
      compareSeatNumbers(`seatNumberRoundTrip_${roundTripLeg + 1}`);
    }
  }

  static expectMultiTravellerSeatMapDetailsArePresent() {
    const seatNumbers = ['seatNumberFound1', 'seatNumberFound2'];
    seatNumbers.forEach((cacheKey, index) => {
      cy.task('getDataFromCache', cacheKey).then((seatNumber: any) => {
        cy.log(`Seat number found ${index + 1}: ${seatNumber}`);
        cy.get(tripItinerarySelectors.seatNumber).should('contain', seatNumber);
      });
    });
  }

  static expectOperatorIconIsPresent() {
    cy.get(tripItinerarySelectors.operatorLogo).should('be.visible');
    cy.allure().logStep('Expect operator logo is present');
  }

  static expectTrainDepartureDateIsCorrect() {
    cy.get(tripItinerarySelectors.departureDateInfo)
      .eq(0)
      .invoke('text')
      .then((departureDateFound) => {
        cy.log(departureDateFound);
        cy.task('getDataFromCache', 'departureDate').then((departureDateText: any) => {
          expect(departureDateText.trim()).to.equal(departureDateFound.trim());
        });
      });
  }

  static expectETicketIsDownloadable() {
    cy.get(tripItinerarySelectors.eTicket).should('not.be.disabled');
    cy.allure().logStep('Expect e-ticket is downloadable');
    cy.get(tripItinerarySelectors.ETicketDisabled).should('not.exist');
    cy.get(tripItinerarySelectors.eventActionDownloadETicketRail).should('not.contain', ' E-Ticket in progress ');
    cy.get(tripItinerarySelectors.eventActionDownloadETicketRail).should('not.contain', ' E-Ticket');
  }
}
