import moment = require('moment');

import { Utility, utilitySelector, Timeouts } from '@utility-lib/index';
import { hotelCheckoutSelector } from '@hotel-lib/index';
import { BlackCarLocation } from '@blackCar-lib/type/black_cars_location.type';
import { Interception } from 'cypress/types/net-stubbing';
import { TripTileType } from '@utility-lib/index';

const blackCarCheckout = {
  saveTripInfo: '[qaid="tripCheckoutCreateButton"]',
  acknowledgement: '[qaid="carCheckoutSummary"] .mat-checkbox-inner-container',
  bookNow: '[qaid="infoBannerPrimaryButton"]',
  bookingSuccessMsg: 'ta-booking-success-modal',
  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: '[formcontrolname="reason"]',
  outOfPolicyAcknowledgment: '[qaid="carOutOfPolicy"] .mat-checkbox-inner-container',
  outOfPolicyContinue: '[qaid="carOutOfPolicy"] [theme="primary"]',
  confirmApproval: '.hard-approval-explanation-modal [tamodalprimaryaction]',
  viewItineraryButton: 'ta-booking-success-modal button',
  timeAndLocationsRows:
    '.black-car-checkout__time-location-info .black-car-checkout__info-row',
  flightDetailsCard: '.black-car-checkout__flight-info-card',
  importantBookingDetailsText:
    'ta-checkout-card[title="Important booking details"] .black-car-checkout__booking-details',
  tripRenameButton: '[qaid="tripCheckoutRenameButton"]',
  estimatedTotalValue: '.black-car-checkout__est-total div span',
  paymentMethod: '.ta-payment-at-booking .ta-payment-card__name',
  seeMoreCars: '.information__footer .ta-button__content',
  tripFee: '[title="Trip fee"]',
  successModel: '[data-testid="bookingSuccessModalTitle"]'
};

export class BlackCarCheckout {
  static waitToBeLoaded(isNeedWaitMatchingTrips = true): void {
    cy.allure().logStep('wait for cars checkout page APIs to complete');
    cy.wait('@waitForBlackCarContract');
    if (isNeedWaitMatchingTrips) {
      cy.wait('@waitForBlackCarMatchingTrips');
    }
  }

  static setTripInfo() {
    cy.get(blackCarCheckout.paymentMethod).should('be.visible');
    Utility.saveTripInformation();
    const maxRetryCount = 3;
    let retryCount = 0;
    cy.get(utilitySelector.bodySelector).then(($body) => {
      if ($body.find(blackCarCheckout.saveTripInfo).length > 0) {
        Utility.saveTripInformation();
      } else {
        retryCount++;
        if (retryCount < maxRetryCount) {
          cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
          Utility.saveTripInformation();
        } else {
          cy.log('Trip info is not loaded');
        }
      }
    });
  }

  static verifyTripInfoActionsIsNotVisible() {
    cy.allure().logStep('verify trip info actions is not visible');
    cy.get(utilitySelector.saveTripInfo).should('not.exist');
    cy.get(blackCarCheckout.tripRenameButton).should('not.exist');
  }

  static verifyImportantNotesDisclaimer(disclaimer: string) {
    cy.allure().logStep(
      `verify important notes section on checkout page should contain: ${disclaimer}`
    );
    cy.get(blackCarCheckout.importantBookingDetailsText).contains(disclaimer);
  }

  static setAcknowledgement() {
    cy.allure().logStep('accept acknowledgement');
    cy.get(blackCarCheckout.paymentMethod).should('be.visible');
    cy.get(blackCarCheckout.acknowledgement).click();
  }

  static checkOutCar(saveBookingId = false, tripTileType?: TripTileType) {
    const maxRetryCount = 3;
    let retryCount = 0;

    const checkoutCarRequest = () => {
      if (tripTileType === 'Business') {
        cy.get(blackCarCheckout.tripFee).should('be.visible');
      }

      cy.get(blackCarCheckout.bookNow).contains(' Book now ').click({ force: true });
      cy.clickIfExist(blackCarCheckout.confirmApproval, Timeouts.SHORT_TIMEOUT_3_SEC);
      cy.wait('@waitForCheckout').then((Interception: Interception) => {
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        cy.get(utilitySelector.bodySelector).then(($body) => {
          if ($body.find(utilitySelector.warningMsg).length > 0) {
            cy.log(`Checkout failed. Retrying... ${retryCount} times`);
            retryCount++;
            if (retryCount < maxRetryCount) {
              cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
              cy.get('body').then(($body) => {
                if ($body.find(blackCarCheckout.successModel).length) {
                  cy.log('Checkout successful');
                } else {
                  cy.get(blackCarCheckout.seeMoreCars).eq(1).click();
                  cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
                  checkoutCarRequest();
                }
              });
            } else {
              cy.log(
                `Maximum retry count reached. Checkout failed. Retried ${retryCount} times.`
              );
            }
          } else {
            cy.log('Checkout successful');
            if (saveBookingId) {
              cy.task('putDataInCache', {
                key: 'blackCarBookingId',
                data: Interception.response?.body.bookingUuid
              });
            }
          }
        });
      });
    };

    checkoutCarRequest();
  }

  static expectBlackCarBookingSuccessfully() {
    cy.get(blackCarCheckout.bookingSuccessMsg, Timeouts.MEDIUM_TIMEOUT_60_SEC).should(
      'be.visible'
    );
    cy.allure().logStep('Black car successfully booked');
  }

  static visitItineraryPageFromBookingSuccessModal() {
    cy.allure().logStep('visit itinerary page from booking success modal');
    cy.get(blackCarCheckout.viewItineraryButton).contains('View itinerary').click();
  }

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

  static verifyLocation(location: string) {
    cy.allure().logStep(`verify location "${location}" exist on checkout page`);
    cy.get(blackCarCheckout.timeAndLocationsRows).should('contain', location);
  }

  static verifyPickUpDate(pickUpDateCached: string) {
    cy.allure().logStep('verify pick-up date on checkout page');
    cy.get(blackCarCheckout.timeAndLocationsRows).then((element) => {
      const pickUpTime = moment(pickUpDateCached).format('h:mm a');
      const pickUpDate = moment(pickUpDateCached).format('dddd, MMMM D, YYYY');
      expect(element, `checkout page should contain pick-up time: ${pickUpTime}`).contain(
        pickUpTime
      );
      expect(element, `checkout page should contain pick-up date: ${pickUpDate}`).contain(
        pickUpDate
      );
    });
  }

  static verifyFlightDetails(location: BlackCarLocation) {
    if (location.airlineInfo) {
      const airlineName = location.airlineInfo.airlineName;
      const flightNumber = location.airlineInfo.flightNumber;
      cy.allure().logStep('verify flight details on checkout page');
      cy.get(blackCarCheckout.flightDetailsCard).then((element) => {
        expect(
          element,
          `checkout page should contain airline name: ${airlineName}`
        ).contain(airlineName);
        expect(
          element,
          `checkout page should contain flight number: ${flightNumber}`
        ).contain(flightNumber);
      });
    }
  }

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

  static storeEstimatedTotal() {
    cy.allure().logStep('store estimated total');
    cy.get(blackCarCheckout.estimatedTotalValue)
      .eq(0)
      .then((element) => {
        cy.task('putDataInCache', {
          key: 'estTotal',
          data: element.text().trim()
        });
      });
  }

  static expectPaymentMethodPresent() {
    cy.get(blackCarCheckout.paymentMethod).should('be.visible');
  }
}
