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

type tripTab = 'Upcoming' | 'Past' | 'Canceled';
type tripStatus = 'Pending Approval' | 'Rejected' | 'Approved';

const rentalCarTripsSelectors = {
  viewAndManageOption: 'button[qaid="goToItinerary"]',
  tipTimeLine: '.trip-timeline__list',
  itineraryBodyStatus: '.itinerary__content-body__item',
  goToItinerary: '[qaid="goToItinerary"]',
  appliedLoyaltyName: '.ta-loyalty-card__card-name',
  driverName:
    '[class="trip-event-card-car-list__content trip-event-card-car-list__driver"] span',
  tripTab: (tripTab: tripTab) => `button[aria-label="${tripTab}"]`,
  tripTile: '[class="ta-trips-card-loading"]',
  backToItineraryButton: '[class="itinerary-information__trips-link"]',
  tripCardTag: '[class^= "navan-trip-card__info__tag"]',
  deliveryAndCollectionLocation: '[class="trip-event-card-car-list__heading"]',
  deliveryCollectionMsg:
    '[class="trip-event-card-car-important-delivery-collect-details__message"]',
  pickupLocation: '[data-testid= "pickUpSection"]',
  dropOffLocation: '[data-testid="dropOffSection"]',
  carType: '[class= "car-basic-info__car-type"]',
  tripEventCard: '[class^="trip-event-card-car-list__content"]',
  hotelIndicator: '[class^="booking-indicator--hotel"]',
  carIndicator: '[class^="booking-indicator--car"]',
  itineraryInfoTittle: '[class^="itinerary-information__title__text"]',
  carIcon: '[icon="booking-type-car"]',
  hotelIcon: '[icon="booking-type-hotel"]',
  tripCard: '[class="navan-trip-card"]'
};

export class Trips {
  static visitTripsPage() {
    Utility.waitForLoadHomePage();
    cy.allure().logStep('visit trips page');
    cy.visit('app/user2/trips');
    cy.wait('@waitForTravellers');
    cy.url().should('include', '/trips');
  }

  static selectTripTab(tripTab: tripTab) {
    cy.allure().logStep(`select ${tripTab}`);
    cy.get(rentalCarTripsSelectors.tripTab(tripTab)).click();
  }

  static selectTrip(existingTrip?: boolean) {
    if (existingTrip) {
      cy.get(
        `${rentalCarTripsSelectors.hotelIndicator},${rentalCarTripsSelectors.carIndicator}`
      ).should('be.visible');
      cy.get(rentalCarTripsSelectors.tripCard).should('have.length', 1);
    }
    cy.allure().logStep('select trip from the search result');
    cy.get(rentalCarTripsSelectors.goToItinerary)
      .should('be.visible')
      .click({ force: true });
    cy.wait('@waitForTravellers');
    cy.url().should('include', 'carUuid=');
  }

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

  static selectTripToManage(index = 0) {
    const retries = 2;
    let retryCount = 0;

    const selectAndClickTrip = () => {
      cy.allure().logStep('select trip to manage');

      cy.get(utilitySelector.bodySelector).then(($body) => {
        if ($body.find(rentalCarTripsSelectors.viewAndManageOption).length > 0) {
          cy.get(rentalCarTripsSelectors.viewAndManageOption)
            .eq(index)
            .click({ force: true });
          cy.log('Trip is found on the page and selected to manage it');
        } else {
          retryCount++;
          cy.log(`Retrying to find the element. Retry count: ${retryCount}`);

          if (retryCount <= retries) {
            cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
            selectAndClickTrip();
          } else {
            cy.log(`Failed to find the element after ${retries} retries.`);
            cy.allure().logStep(`Failed to find the element after ${retries} retries.`);
          }
        }
      });
    };

    selectAndClickTrip();
    cy.url().then((currentUrl) => {
      cy.log(`Current URL is: ${currentUrl}`);
      cy.task('putDataInCache', {
        key: 'tripItineraryUrl',
        data: currentUrl
      });
    });
  }

  static expectDriverNameIsCorrect() {
    cy.task('getDataFromCache', 'travelerName').then((text: any) => {
      cy.get(rentalCarTripsSelectors.driverName).should('contain', text);
    });
  }

  static verifyTripStatus(tripStatus: tripStatus) {
    cy.allure().logStep(`verify if trip status is equal "${tripStatus}"`);
    if (tripStatus === 'Approved') {
      cy.get(rentalCarTripsSelectors.itineraryBodyStatus)
        .should('not.contain.text', 'Pending Approval')
        .and('not.contain.text', 'Rejected');
    } else {
      cy.get(rentalCarTripsSelectors.itineraryBodyStatus).should(
        'contain.text',
        tripStatus
      );
    }
  }

  static validateTripDetails() {
    this.visitTripsPage();
    this.selectTripToManage();
    this.expectDriverNameIsCorrect();
  }

  static canceledTrip(retryCount = 0) {
    const maxRetries = 3;

    cy.allure().logStep('Select canceled trip to manage');
    cy.task('getDataFromCache', 'rentalCarTripItineraryUrl').then((url) => {
      cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);

      cy.visit(url as string);
      cy.log('New URL is ' + url);
      cy.wait('@waitForLoadTripPage');
      cy.get(utilitySelector.bodySelector).then((body) => {
        if (body.text().includes('Rejected')) {
          cy.log('Trip is canceled');
        } else {
          if (retryCount < maxRetries) {
            cy.log(
              `Trip is not canceled. Retrying (${retryCount + 1} of ${maxRetries})...`
            );
            cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
            cy.reload();
            cy.wait('@waitForLoadTripPage');
            this.canceledTrip(retryCount + 1);
          } else {
            cy.log(`Trip is not canceled after ${maxRetries} retries.`);
          }
        }
      });
    });
  }
  static expectDeliveryAndCollectIsPresent() {
    cy.get(rentalCarTripsSelectors.deliveryAndCollectionLocation)
      .should('contain', 'Delivery')
      .and('contain', 'Collection');
  }

  static expectCollectionImportantMsgIsPresent() {
    cy.get(rentalCarTripsSelectors.deliveryCollectionMsg)
      .should('contain', deliveryAndCollectInfo[0])
      .and('contain', deliveryAndCollectInfo[1]);
  }
  static expectDeliveryAndCollectLocationIsPresent() {
    cy.task('getDataFromCache', 'hotelLocation').then((hotelLocation: any) => {
      const parsedHotelLocation = JSON.parse(hotelLocation);
      cy.get(rentalCarTripsSelectors.pickupLocation).should(
        'contain',
        parsedHotelLocation
      );
      cy.get(rentalCarTripsSelectors.dropOffLocation).should(
        'contain',
        parsedHotelLocation
      );
    });
  }

  static expectCarTypeIsPresent() {
    cy.task('getDataFromCache', 'selectedCarType').then((carType: any) => {
      cy.get(rentalCarTripsSelectors.carType).should('contain', carType);
    });
  }

  static expectEstimatedCostIsCorrect() {
    cy.task('getDataFromCache', 'estTotal').then((estTotalCached: any) => {
      cy.log('cached estimated total: ' + estTotalCached);

      cy.get('[data-testid="bookingPrice"]').should(($element) => {
        const elementText = $element.text().replace(/\s/g, '');
        const cachedText = estTotalCached.replace(/\s/g, '');

        expect(elementText).to.include(cachedText);
      });
      expect(estTotalCached, 'cached estimated total should not be null').to.not.be.null;
    });
  }

  static expectPaymentTypeIsDirectBill() {
    cy.get(rentalCarTripsSelectors.tripEventCard).should('contain', 'Direct Bill');
  }

  static expectTripTitleNameIsCorrect() {
    cy.task('getDataFromCache', 'itineraryTitle').then((hotelTripTitle) => {
      cy.log('<<< Itinerary Title is >>>: ' + hotelTripTitle);
      cy.get(rentalCarTripsSelectors.itineraryInfoTittle)
        .invoke('text')
        .then((hotelTripTitle) => {
          cy.log('<<< Current Itinerary Title is >>>: ' + hotelTripTitle);
          expect(hotelTripTitle).to.equal(hotelTripTitle);
        });
    });
  }

  static expectRentalCarAndHotelItineraryIsPresent() {
    cy.get(
      `${rentalCarTripsSelectors.carIcon},${rentalCarTripsSelectors.hotelIcon}`
    ).should('be.visible');
    cy.get(rentalCarTripsSelectors.hotelIcon).should('be.visible');
  }
}
