import moment = require('moment');

import { Logs, Utility, TripTileType, Timeouts } from '@utility-lib/index';
import { BlackCarLocation } from '@blackCar-lib/index';

type callback = (value: string) => void;

export const blackCarSelector = {
  location: '[formcontrolname="pickUpLocation"] input',
  calendarButton: '[class^="ta-date-trigger-v2 ta-date"]',
  nextMonthCalendarButton:
    '[class="popover popover-calendar enter"] [aria-label="next month"]',
  tripCheckoutAddToTrip: '[qaid="tripCheckoutAddToTrip"]',
  dropDownButton: '.ta-select-option',
  dropOffSelect: '[qaid="carDropOffTypeSelect"]',
  tripTypeSelection: '[qaid="hourlyTypeSelect"]',
  linkFlightModal: 'ta-link-flight-modal',
  airlineNameInput: '[formcontrolname="airline"] input',
  flightNumberInput: 'input[formcontrolname="flightNumber"]',
  linkButton: 'ta-link-flight-modal button',
  popoverContent: '.popover-content',
  popoverContentAirlineName: (airlineName: string) =>
    `${blackCarSelector.popoverContent} [aria-label^="${airlineName}"]`,
  linkFlightPill: '.search-form-x-v2__extra__pill',
  calendarField: '.ta-date-trigger-v2__date-wrap',
  durationSelection: '[formcontrolname="duration"]',
  taLoginAsPanel: 'ta-login-as .ta-login-as',
  taLoginAsSearchUser: '.ta-login-as__search-user',
  taLoginAsSearchUserInput: '.popover-content ta-form-wrap input',
  taLoginAsSearchUserResult: '.popover-content .ta-search-result',
  userMenuButton: '[data-qaid=USER_MENU-button]',
  selectTripTileType:
    '.home-search-form__options__left-dropdown [icon="dropdown-triangle"]',
  searchBlackCar: '[class="ta-button__content"]',
  verifyLink: '[class^="black-car-search-form__linked-flights__pill"]',
  popoverLocation: (location: string) => `.popover-content [aria-label^="${location}"]`,
  formcontrolNameInput: (dropOffType: string) =>
    `[formcontrolname="${dropOffType}"] input`
};

export enum BlackCarTripType {
  ONEWAY = 'One-way',
  HOURLY = 'Hourly'
}

interface StorableDate {
  pickUpDay: number;
  pickUpHour: number;
  pickUpMinute: number;
}

export class BlackCar {
  static visitBlackCarSearch(tripType: TripTileType) {
    Utility.visitSearchPage();
    Utility.selectVertical('blackCar');
    Utility.selectTripTileType(tripType);
  }

  static selectPickUpLocation(pickUpLocation: string) {
    cy.allure().logStep('Select pick up location');
    this.setLocation(pickUpLocation, 'pickUpLocation');
  }

  static selectDropOffLocation(dropOffLocation: string) {
    cy.allure().logStep('Select drop off location');
    this.setLocation(dropOffLocation, 'dropOffLocation');
  }

  static setAirlineDetailsAndVerify(location: BlackCarLocation) {
    if (location.airlineInfo) {
      cy.allure().logStep('set airline details');
      BlackCar.verifyLinkFlightModalIsVisible();
      BlackCar.setFlightDetails(
        location.airlineInfo.airlineName,
        location.airlineInfo.flightNumber
      );
      BlackCar.verifyLinkFlightIsAdded(
        location.airlineInfo.airlineName,
        location.airlineInfo.flightNumber
      );
    }
  }

  static setLocation(location: string, dropOffType: string) {
    cy.allure().logStep(`set rental car pickup location: ${location}`);
    cy.clearInputAndType(
      blackCarSelector.formcontrolNameInput(dropOffType),
      `${location}`
    );
    cy.wait('@waitForLocation');
    cy.get(blackCarSelector.popoverLocation(location)).eq(0).trigger('click', {
      force: true
    });
  }
  static setPickUpAndDropOffDate() {
    const numberOfMonthsAfterStartDate = 2;
    const newDayOfMonth = 16;
    cy.allure().logStep(
      `set pick up and drop off ${numberOfMonthsAfterStartDate} after months and ${newDayOfMonth} day of month`
    );
    Utility.selectFutureDate(numberOfMonthsAfterStartDate, newDayOfMonth);
    this.storePickUpDate(
      { pickUpDay: newDayOfMonth, pickUpHour: 12, pickUpMinute: 0 },
      numberOfMonthsAfterStartDate
    );
  }

  static searchBlackCar() {
    cy.allure().logStep('search black car');
    cy.get(blackCarSelector.searchBlackCar).contains(' Search ').click();
    cy.wait('@waitForBlackCarSearch').then((xhr) => {
      Logs.cypressResponseLog('SEARCH BLACK CAR RESPONSE', xhr);
    });
  }

  static selectTripTileType(tripType: BlackCarTripType) {
    cy.allure().logStep(`Select trip type: ${tripType}`);
    cy.get(blackCarSelector.selectTripTileType).click();

    switch (tripType) {
      case BlackCarTripType.ONEWAY:
        cy.get(blackCarSelector.dropDownButton).eq(0).click();
        break;
      case BlackCarTripType.HOURLY:
        cy.get(blackCarSelector.dropDownButton).eq(1).click();
        break;
    }
  }

  static selectDuration(hours = 2) {
    cy.allure().logStep(`select duration: ${hours}`);
    cy.get(blackCarSelector.durationSelection).click();
    cy.get(blackCarSelector.dropDownButton).contains(`${hours} hours`).click();
  }

  static verifyLinkFlightModalIsVisible() {
    cy.allure().logStep('verify link flight modal is visible');
    cy.get(blackCarSelector.linkFlightModal).should('be.visible');
  }

  static setFlightDetails(airlineName: string, flightNumber: string) {
    cy.allure().logStep(
      `fill flight details in link flight modal with data: airline name: ${airlineName} and flight number: ${flightNumber}`
    );
    cy.get(blackCarSelector.airlineNameInput).type(airlineName);
    cy.wait('@waitForAirlines');
    cy.get(blackCarSelector.popoverContentAirlineName(airlineName))
      .eq(0)
      .trigger('click', {
        force: true
      });
    cy.get(blackCarSelector.flightNumberInput).type(flightNumber);
    cy.get(blackCarSelector.linkButton).contains('Link').click();
  }

  static verifyLinkFlightIsAdded(airlineName: string, flightNumber: string) {
    cy.allure().logStep(`verify link a flight ${airlineName} ${flightNumber} is added`);
    cy.get(blackCarSelector.verifyLink)
      .contains(`${airlineName} ${flightNumber}`)
      .should('be.visible');
  }

  static storePickUpDate(storableDate: StorableDate, additionalMonth = 0) {
    cy.allure().logStep('store pick-up date on search page');
    const { pickUpDay, pickUpHour, pickUpMinute } = storableDate;
    const datePickUp = moment()
      .set('date', pickUpDay)
      .set('hour', pickUpHour)
      .set('minute', pickUpMinute)
      .add(additionalMonth, 'month');
    cy.task('putDataInCache', {
      key: 'pickUpDate',
      data: datePickUp.toString()
    });
  }

  static getDataFromCachedPickUpDateAndPassToFunction(callbackFunction: callback) {
    cy.allure().logStep('get pick-up date from cache');
    cy.task('getDataFromCache', 'pickUpDate').then((pickUpDateCached: any) => {
      const date = pickUpDateCached ? pickUpDateCached : null;
      expect(date, 'cached pick up date should not be null').to.not.be.null;
      callbackFunction(date);
    });
  }

  static loginAsDelegatedUser() {
    cy.allure().logStep(
      'login as traveler from "login as" panel to make delegate booking'
    );
    cy.get(blackCarSelector.taLoginAsPanel).should('be.visible');
    cy.task('getDataFromCache', 'travelerEmail').then((email: any) => {
      cy.get(blackCarSelector.taLoginAsSearchUser).click();
      cy.get(blackCarSelector.taLoginAsSearchUserInput).type(email);
      cy.wait('@waitForDelegatedUsers');
      cy.get(blackCarSelector.taLoginAsSearchUserResult).contains(email).click();
    });
  }

  static waitSearchPageIsReloaded() {
    Utility.waitForLoadHomePage();
    cy.wait('@waitForVisitPage');
    cy.location('pathname', Timeouts.MEDIUM_TIMEOUT_60_SEC).should(
      'include',
      'app/user2/home'
    );
  }

  static waitUserInfoAndVerifyIt() {
    cy.wait('@waitForUserInfo').then((xhr) => {
      const fullName = xhr.response?.body.name;
      this.verifyLoggedInAsDelegatedUser(fullName);
      cy.task('putDataInCache', {
        key: 'delegatedUserName',
        data: fullName
      });
    });
  }

  static verifyLoggedInAsDelegatedUser(userName: string) {
    cy.get(blackCarSelector.userMenuButton)
      .should('contain', 'Logged in as')
      .and('contain', userName);
  }
}
