import { UtilityIntercept } from './api-intercept';
import { TripTileType, verticalType, Timeouts } from '@utility-lib/constants';
import { Interception } from 'cypress/types/net-stubbing';
import { Logs } from './log';

type navigation = 'HOME' | 'TRIPS' | 'EVENTS' | 'OFFICE_GUIDES' | 'HELP';

export type DaysToMove = {
  daysToMove: number;
  daysAfterMovedDays: number;
};

export const utilitySelector = {
  businessTypeSelect: '[class^="trip-type-select__container"]',
  tripCheckoutAddToTrip: '[qaid="tripCheckoutAddToTrip"]',
  createNewTrip: '[qaid="tripCheckoutCreateNewTrip"]',
  saveTripInfo: '[qaid="tripCheckoutCreateButton"]',
  dropDownButton: '.ta-select',
  tripCheckoutSelect: '.ta-trip-checkout__select',
  nextMonthCalendarButton: '[class="popover popover-calendar enter"] [class$="ta-calendar__handle--right"]',
  calendarButton: '[class^="ta-date-trigger"] [class^="ta-date-trigger"][class$="text"]',
  calendarInputText: '[class^="ta-date-trigger"] [class^="ta-date-trigger"][class$="text"] [class*="__date-wrap"]',
  calendarText: '[class^="ta-date-trigger"] .ta-date-trigger__text',
  selectDate: '[data-testid="calendarDay"]',
  closeCalendar: '.popover-content [type="submit"]',
  startDayRangeCalendar: 'div.ta-calendar-day--range-start',
  searchLoader: '.ta-search__content',
  searchLoaderPersonal: '.ta-lottie-search__content',
  warningMsg: '[class^="ta-toastr-event__message"]',
  chatBoxCLoseButton: '#ta-chat [href="#"]',
  upgradeLiquidCardPopup: '[title^="Upgrade to TripActions Liquid and get"] .ta-trip-group__group',
  dismissLiquidCardPopup: '.trip-type-selection__group-container__actions',
  bookingTypeTitle: '.ta-trip-tile__title',
  bookingType: '[class^="ta-tabs__item"]',
  searchLocationInput: '.search-form-container-minimized__fake-form__text',
  checkoutSummary: '[class="booking-item"]',
  tripTile: (tripType: TripTileType) =>
    `[class^="search-form-container__header__theme-selector"] [aria-label=${tripType}]`,
  tripsOnTripPage: '.booking-complete-others__left__buttons > :nth-child(2) > :nth-child(2)',
  firstTripOnTripPage: 'ta-trip-card-v2',
  eventsPageTab: '[data-qaid="EVENTS"]',
  ariaLabel: (name: string) => `[aria-label*="${name}"]`,
  dropdownLocation: (location: string) => `.popover-content [aria-label^="${location}"]`,
  cancellationReasonDropdown: '[formcontrolname="selectedReason"] [type="button"]',
  cancelConfirm: '[qaid="cancelBookingButton"]',
  canceledLabel: '[class^="booking-status-tag"]',
  canceledWarning: '[class^="booking-status-tag"] span',
  iframe: '#invoiceIframe',
  selectTripOnTripPage: '[qaid="goToItinerary"]',
  popUpCancel: '[qa-id="event-action-cancel-train"]',
  dataTestID: (name: string) => `[data-testid="${name}"]`,
  closePersonalTravelerInputModal: '.ta-button__content',
  buttonClass: '.ta-button-v2',
  closeTravelerInputModal: '.ta-chevron-toggle__icon.ta-chevron-toggle__icon--expanded',
  navTypeItem: (navType: string) => `[data-qaid="${navType}"]`,
  eventActionCancel: (vertical: string) => `[qaid="eventActionCancel${vertical}"]`,
  eventActionChange: (vertical: string) => `[qaid="eventActionChange${vertical}"]`,
  cancellationReason: (reason: string) => `[aria-label="${reason}"]`,
  adminNav: (adminNav: string) => `[data-qaid="${adminNav}"] button`,
  adminDropDownButton: (dropDownButton: string) => `[data-qaid="${dropDownButton}"]`,

  bodySelector: 'body',
  tableRowSelector: 'tr',
  listItemSelector: 'li',
  buttonSelector: 'button',
  spanSelector: 'span',
  inputSelector: 'input',
  imageSelector: 'img',
  paragraphSelector: 'p'
};

export class Utility {
  static selectTripTileType(tripType: TripTileType): void {
    cy.get(utilitySelector.tripTile(tripType), Timeouts.MEDIUM_TIMEOUT_60_SEC).click({
      force: true
    });
    cy.allure().logStep(`${tripType} selected`);
  }

  static selectBusinessType(bookingType: TripTileType) {
    cy.get(utilitySelector.searchLocationInput).click();
    cy.get(utilitySelector.bookingType).contains(bookingType).click({ force: true });
  }

  static setTripInfo() {
    cy.allure().logStep('set trip information');
    cy.get(utilitySelector.tripCheckoutAddToTrip || utilitySelector.saveTripInfo, Timeouts.MAX_TIMEOUT_120_SEC);
    this.closeIfChatBoxIsOpen();
    cy.get(utilitySelector.bodySelector).then(($body) => {
      if ($body.text().includes(' Add to this trip ')) {
        cy.get(utilitySelector.tripCheckoutAddToTrip).contains(' Add to this trip ').click();
        cy.allure().logStep('add to this trip');
      } else {
        cy.allure().logStep('save trip information');
        cy.get(utilitySelector.dropDownButton).click();
        cy.intercept('POST', /api\/v1\/trip\/tripFee\/searches/).as('waitForSaveInfo');
        cy.get(utilitySelector.saveTripInfo).contains(' Save trip info ').click();
        cy.wait('@waitForSaveInfo');
      }
    });
  }

  static saveTripInformation() {
    cy.clickIfExist(utilitySelector.saveTripInfo, Timeouts.MEDIUM_TIMEOUT_60_SEC);
  }

  static createNewTrip() {
    cy.clickIfExist(utilitySelector.createNewTrip, Timeouts.MEDIUM_TIMEOUT_60_SEC);
  }

  static selectVertical(tab: verticalType) {
    cy.allure().logStep(`select search type: ${tab}`);
    cy.get(utilitySelector.searchLocationInput, Timeouts.MEDIUM_TIMEOUT_60_SEC).should('be.visible').click();
    cy.get(utilitySelector.dataTestID(tab)).should('be.visible').click();
  }

  static clickLocationInput() {
    cy.allure().logStep('click on the location input');
    cy.get(utilitySelector.searchLocationInput).click();
  }

  static selectLocationFromDropdown(location: string) {
    cy.get(utilitySelector.dropdownLocation(location)).eq(0).trigger('click', {
      force: true
    });
  }

  static selectFutureDate(numberOfMonthsAfterStartDate = 5, newDayOfMonth = 0, numberOfDaysAfterDeparture = 0) {
    cy.allure().logStep(`select ${numberOfMonthsAfterStartDate} months later flight`);
    cy.get(utilitySelector.calendarButton).then((elements) => {
      let dayInMonth = newDayOfMonth > 0 ? newDayOfMonth : 1 + Math.floor(Math.random() * 27);
      for (let i = 0; i < elements.length; i++) {
        cy.get(utilitySelector.calendarButton).eq(i).click();
        if (i === 0) {
          Cypress._.times(numberOfMonthsAfterStartDate, () => {
            cy.get(utilitySelector.nextMonthCalendarButton).click();
          });
        }
        if (dayInMonth > 28) {
          dayInMonth -= 28;
          cy.get(utilitySelector.nextMonthCalendarButton).click();
        }
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        cy.get(utilitySelector.selectDate).contains(dayInMonth).should('be.visible').eq(0).click({ force: true });
        cy.get(utilitySelector.closeCalendar).click();
        if (i === 0 && numberOfDaysAfterDeparture > 0) {
          dayInMonth +=
            numberOfDaysAfterDeparture <= 7 ? numberOfDaysAfterDeparture : 1 + Math.floor(Math.random() * 3);
        } else {
          dayInMonth += Math.ceil(Math.random() * 7);
        }
      }
    });
  }

  static shiftingDates(inputDaysToMove: DaysToMove) {
    const { daysToMove, daysAfterMovedDays } = inputDaysToMove;
    const currDate = new Date();
    const currMonthIndex = currDate.getMonth();
    currDate.setDate(currDate.getDate() + daysToMove);

    // The temporary variable is needed for correct putDataInCache work
    const tempDate = new Date(currDate);
    cy.task('putDataInCache', {
      key: 'selectedCheckInDate',
      data: tempDate
    });
    cy.log('checkInDate: ' + currDate);

    const chosenCheckinDay = currDate.getDate();
    const chosenCheckinMonthIndex = currDate.getMonth();
    const monthsToShift = chosenCheckinMonthIndex - currMonthIndex;
    currDate.setDate(currDate.getDate() + daysAfterMovedDays);

    cy.task('putDataInCache', {
      key: 'selectedCheckoutDate',
      data: currDate
    });
    cy.log('checkoutDate: ' + currDate);

    const chosenCheckoutDay = currDate.getDate();
    const chosenCheckoutMonthIndex = currDate.getMonth();
    const monthsToShiftToCheckoutDay = chosenCheckoutMonthIndex - chosenCheckinMonthIndex;

    return {
      monthsToShift: monthsToShift,
      monthsToShiftToCheckoutDay: monthsToShiftToCheckoutDay,
      chosenCheckinDay: chosenCheckinDay,
      chosenCheckoutDay: chosenCheckoutDay
    };
  }

  static selectShiftedDate(inputDaysToMove: DaysToMove) {
    cy.allure().logStep(`Select dates shifted ${inputDaysToMove.daysToMove} according to today`);
    const shiftedDates = Utility.shiftingDates(inputDaysToMove);

    cy.get(utilitySelector.calendarButton).then((elements) => {
      for (let i = 0; i < elements.length; i++) {
        cy.get(utilitySelector.calendarButton).eq(i).click();
        if (i === 0) {
          if (shiftedDates.monthsToShift > 0) {
            Cypress._.times(shiftedDates.monthsToShift, () => {
              cy.get(utilitySelector.nextMonthCalendarButton).click();
            });
          }
          cy.get(utilitySelector.selectDate).contains(shiftedDates.chosenCheckinDay).eq(0).click();
        } else {
          if (shiftedDates.monthsToShiftToCheckoutDay > 0) {
            Cypress._.times(shiftedDates.monthsToShiftToCheckoutDay, () => {
              cy.get(utilitySelector.nextMonthCalendarButton).click();
            });
          }
          cy.get(utilitySelector.selectDate).contains(shiftedDates.chosenCheckoutDay).eq(0).click();
        }
        cy.get(utilitySelector.closeCalendar).click();
      }
    });
  }

  // workaround for guest invite due to bug GME-2118
  static reselectSelectedDate() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.calendarText).eq(0).click();
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.startDayRangeCalendar).click();
  }

  static openEventsPage() {
    cy.allure().logStep('open events page');
    cy.get(utilitySelector.eventsPageTab).contains('Events').click();
  }

  static openTeamOffsitePage() {
    cy.allure().logStep('open events page');
    cy.get(utilitySelector.eventsPageTab).click();
  }

  static expectSearchLoaderDisabled() {
    cy.allure().logStep('wait until search loader until it disappear');
    cy.get(utilitySelector.searchLoader, Timeouts.MAX_TIMEOUT_120_SEC).should('be.not.exist');
    cy.get(utilitySelector.searchLoaderPersonal, Timeouts.MAX_TIMEOUT_120_SEC).should('be.not.exist');
  }

  static waitUntilWarningMsgDisabled() {
    cy.allure().logStep('wait for warning msg to disappear');
    cy.get(utilitySelector.warningMsg, Timeouts.MAX_TIMEOUT_120_SEC).should('be.not.exist');
  }

  static closeIfChatBoxIsOpen() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.bodySelector).then((chatBox) => {
      if (chatBox.find(utilitySelector.chatBoxCLoseButton).length > 0) {
        cy.get(utilitySelector.chatBoxCLoseButton).click();
      } else {
        cy.log('chat box not opened');
      }
    });
  }

  static visitSearchPage(retryCount = 3) {
    cy.allure().logStep('visit search page');
    cy.visit('app/user2/home');
    this.waitForLoadHomePage();
    cy.url()
      .should('include', '/home', Timeouts.MEDIUM_TIMEOUT_60_SEC)
      .then((urlCheck) => {
        if (!urlCheck && retryCount > 0) {
          cy.log(`<<<<<<<< Retry attempt >>>>>>>>>: ${retryCount}`);
          this.visitSearchPage(retryCount - 1);
          cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
          this.waitForLoadHomePage();
        }
      });
  }

  static verifyPageTitle(title: string) {
    cy.title().should('eq', title);
  }

  static selectNavItem(navType: navigation) {
    cy.get(utilitySelector.navTypeItem(navType)).trigger('click');
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
  }

  static changeBrowserLanguageTo(language: string) {
    cy.log('Changing browser language to DE');
    cy.on('window:before:load', (win) => {
      Object.defineProperty(win.navigator, 'languages', {
        value: [language, 'en', 'en-US']
      });
      Object.defineProperty(win.navigator, 'language', {
        value: language
      });
    });
  }

  static waitForLoadHomePage() {
    UtilityIntercept.interceptBaseApis();
  }

  static openTrip() {
    cy.log('Opening trip from trip page');
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.tripsOnTripPage).click();
    cy.get(utilitySelector.selectTripOnTripPage, Timeouts.MEDIUM_TIMEOUT_60_SEC).should('be.visible').eq(0).click();
  }

  static cancelTrip(vertical: string) {
    cy.allure().logStep('cancel hotel');
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.eventActionCancel(vertical)).should('be.visible').click();
  }

  static selectCancellationReason(reason: string) {
    cy.allure().logStep(`select cancellation reason ${reason}`);
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.cancellationReasonDropdown).click();
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);

    cy.get(utilitySelector.cancellationReason(reason)).click({
      force: true
    });
  }

  static confirmCancellation() {
    cy.allure().logStep('Confirm Cancellation');
    cy.get(utilitySelector.cancelConfirm).click();
    cy.wait('@waitForCancelBooking').then((interception) => {
      const status = interception.response?.statusCode;
      cy.log(` ---->>> Cancellation status code: ${status} <<<----`);
    });
  }

  static confirmFlightCancellation() {
    cy.allure().logStep('confirm cancellation');
    cy.get(utilitySelector.cancelConfirm).click();
  }

  static expectCancelledLabelIsPresent() {
    cy.allure().logStep('expect cancelled label is present');
    cy.get(utilitySelector.canceledLabel).should('contain', 'Canceled');
    cy.get(utilitySelector.canceledWarning).should('contain', 'Canceled');
  }

  static getIframeDocument() {
    return cy.get(utilitySelector.iframe).its('0.contentDocument').should('exist');
  }

  static getIframeBody() {
    return this.getIframeDocument().its(utilitySelector.bodySelector).should('not.be.undefined').then(cy.wrap);
  }

  static changeTrip(vertical: string) {
    cy.get(utilitySelector.eventActionChange(vertical)).click();
  }

  static selectAdminNav(adminNav: string, dropDownButton: string) {
    cy.allure().logStep(`select ${adminNav}`);
    cy.get(utilitySelector.adminNav(adminNav)).click();
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(utilitySelector.adminDropDownButton(dropDownButton)).click();
  }

  static loginAsAdmin(password: any) {
    cy.clearLocalStorage();
    cy.clearCookies();
    cy.clearLocalStorage();
    cy.task('getDataFromCache', 'companyCreationEmail').then((email: any) => {
      cy.loginWithAuthToken({ email, password });
      cy.allure().logStep(`logged in as admin: ${email}`);
    });
  }

  static addAmexBTAEUPaymentUuId(amexBTAPlatformType: any) {
    cy.task('getDataFromCache', 'paymentMethodUuId').then((paymentMethodUuId: any) => {
      cy.addAmexBTAEUPaymentUuId(paymentMethodUuId, amexBTAPlatformType);
    });
  }

  static confirmHotelCancellation() {
    cy.allure().logStep('confirm cancellation');
    cy.get(utilitySelector.cancelConfirm).click();
  }

  static createEntity(creds: any, legalEntitiesData: any) {
    cy.clearLocalStorage();
    cy.clearCookies();
    cy.clearLocalStorage();
    cy.task('getDataFromCache', 'companyCreationEmail').then((email: any) => {
      cy.createCompanyLegalEntity(email, creds, legalEntitiesData);
      cy.allure().logStep(`logged in as admin: ${email}`);
    });
  }
  static getXmlContentFromCache(cacheKey: string) {
    cy.allure().logStep('Get XML content from cache');
    return cy.task('getDataFromCache', cacheKey).then((response: any) => {
      const xmlContent = response.xmlReports[0];
      return xmlContent;
    });
  }
  static parseXmlContent(xmlContent: string): Document {
    const parser = new DOMParser();
    const xmlDoc = parser.parseFromString(xmlContent, 'text/xml');
    return xmlDoc;
  }

  static normalizeText(text: string) {
    cy.allure().logStep(`Normalize text: ${text}`);
    const normalizedText = text
      .trim()
      .normalize('NFD')
      .replace(/[\u0300-\u036f]/g, '');
    return normalizedText;
  }

  static closeSurveyIfExists() {
    cy.document().then((doc) => {
      const surveyClose = utilitySelector.dataTestID('surveyClose');
      if (doc.querySelector(surveyClose)) {
        cy.get(surveyClose).then((elements) => {
          console.log({ elements });
          for (let i = 0; i < elements.length; i++) {
            cy.get(surveyClose).eq(i).click();
          }
        });
      }
    });
  }
}
