import {
  RentalCar,
  RentalCarSearchResults,
  RentalCarCheckout,
  RentalCarInterceptApis,
  Trips,
  RentalCarItinerary,
  RentalCarFilters,
  RetryRentalCarModel
} from '@rentalCar-lib/index';
import { TripTileType, Random, LocationUtility, Timeouts } from '@utility-lib/index';
import { LoginPage } from '@admin-lib/index';
import { Provider_Type, User_Type } from '@support-onboard/index';
import { rentalCarSelector } from '@rentalCar-lib/search';
import { rentalCarCheckout } from '../lib/checkout';
import { rentalCarSearchResultSelector } from '@rentalCar-lib/search_results';

export enum RentalCarLocationType {
  airport = 'Airport',
  office = 'Office',
  hotelUS = 'HotelUS',
  general = 'General Location',
  hotelEU = 'HotelEU'
}
export enum RentalCarDropOffType {
  sameDropOff = 'Same drop-off',
  differentDropOff = 'Different drop-off',
  deliverAndCollect = 'Deliver and collect'
}

export const amadeusRentalCarParams: RentalCarParams = {
  tripTileType: 'Business',
  dropOffType: RentalCarDropOffType.deliverAndCollect,
  pickUpLocation: LocationUtility.getHotelEU(),
  outOfPolicy: 'No',
  dropOffLocation: LocationUtility.getHotelEU(),
  rentalCarLocationType: RentalCarLocationType.hotelEU
};

export interface RentalCarParams {
  tripTileType: TripTileType;
  dropOffType: RentalCarDropOffType;
  pickUpLocation: string;
  outOfPolicy?: string;
  dropOffLocation?: string;
  rentalCarLocationType?: RentalCarLocationType;
  directBill?: boolean;
  rentalCarOperator?: string;
  invalidCard?: boolean;
  existingTrip?: boolean;
  policyType?: string;
}

const expectedDetails = ['Delivery and collect address:', 'Delivery date and time:', 'Collection date and time:'];

export const deliveryAndCollectInfo = [
  ` For the vehicle's delivery, the driver must have their credit card, driver's license, and identification ready. `,
  ` The driver must be present when the vehicle is delivered. `
];

export class RentalCarUtility {
  static bookRentalCar(params: RentalCarParams) {
    const {
      tripTileType,
      dropOffType,
      outOfPolicy,
      rentalCarLocationType,
      directBill,
      rentalCarOperator,
      invalidCard,
      existingTrip,
      policyType
    } = params;

    if (existingTrip) {
      RentalCarUtility.setupExistingTrip(params);
    } else {
      RentalCarUtility.setupNewTrip(params);
    }

    RentalCar.searchRentalCar();

    if (directBill && rentalCarOperator) {
      RetryRentalCarModel.searchAndSelectCarOperator(rentalCarOperator);
      cy.get(rentalCarSearchResultSelector.directBillTags).should('contain', 'Direct Bill');
    }

    if (dropOffType === RentalCarDropOffType.deliverAndCollect) {
      RentalCarUtility.handleDeliveryAndCollect();
    }

    if (outOfPolicy === 'Yes') {
      if (policyType === 'cost') {
        RentalCarSearchResults.expectPolicyMaximumPriceIs();
        RentalCarSearchResults.expectOutOfPolicyIconAndReasonIsPresent(
          'Exceeds the $5/day price limit for this booking'
        );
      } else if (policyType === 'class') {
        RentalCarFilters.selectCarType();
        RentalCarSearchResults.expectOutOfPolicyIconAndReasonIsPresent('This car class type is out of your policy.');
      }
    }

    RentalCarFilters.selectAgency();

    RentalCarSearchResults.selectCar();
    RentalCarCheckout.waitToBeLoaded();
    RentalCarCheckout.setTripInfo();

    if (dropOffType === RentalCarDropOffType.deliverAndCollect) {
      RentalCarUtility.expectDeliveryAndCollectInfoIsPresent();
    }

    if (outOfPolicy === 'Yes') {
      RentalCarCheckout.setOutOfPolicyReason();
      RentalCarCheckout.updateEmailDetails('dummy-' + Random.randomString(12) + '@staging-prime.tripactions.xyz');
    }

    if (tripTileType === 'Personal') {
      RentalCarCheckout.updateEmailDetails('personal-' + Random.randomString(12) + '@staging-prime.tripactions.xyz');
    }

    if (dropOffType !== RentalCarDropOffType.deliverAndCollect) {
      cy.log('Acknowledging the terms and conditions');
      cy.checkIfExist(rentalCarCheckout.acknowledgement);
    }

    if (directBill === true && rentalCarOperator) {
      cy.get('[class^="ta-car-tags__container"]').should('contain', 'Direct Bill');
    }

    RentalCarCheckout.checkOutCar(outOfPolicy === 'Yes', rentalCarLocationType, dropOffType, invalidCard);
  }

  static setupExistingTrip(params: RentalCarParams) {
    const { existingTrip } = params;
    if (existingTrip) {
      cy.wait(Timeouts.SHORT_TIMEOUT_2_SEC.timeout);
      cy.task('getDataFromCache', 'hotelLocation').then((hotelLocation: any) => {
        cy.clearInputAndType(rentalCarSelector.location, hotelLocation);
        cy.wait('@waitForLocation');
        cy.get(rentalCarSelector.locationInput).eq(0).trigger('click', {
          force: true
        });
      });
    }
  }

  static setupNewTrip(params: RentalCarParams) {
    const { tripTileType, dropOffType, pickUpLocation, dropOffLocation } = params;
    RentalCar.visitRentalCarSearch(tripTileType);
    RentalCar.selectDropOffType(dropOffType);
    RentalCar.selectPickUpLocation(pickUpLocation);

    if (dropOffType === RentalCarDropOffType.differentDropOff && dropOffLocation) {
      RentalCar.selectDropOffLocation(dropOffLocation);
    } else if (dropOffType === RentalCarDropOffType.deliverAndCollect) {
      cy.get(rentalCarSelector.dAndCInfo).should('be.exist');
    }

    RentalCar.setPickUpAndDropOffDate();
  }

  static handleDeliveryAndCollect() {
    RentalCarFilters.selectRentalCarOperator('Sixt');
    RentalCarSearchResults.getCarLocation();
    cy.get(rentalCarSearchResultSelector.dAndCLocationButton).eq(0).click();
    cy.get(rentalCarSearchResultSelector.locationDetail).each((detailElement, index) => {
      cy.wrap(detailElement).should('contain', expectedDetails[index]);
    });
    cy.task('getDataFromCache', 'hotelLocation').then((hotelLocation: any) => {
      cy.get(rentalCarSearchResultSelector.hotelLocationsPopup).should('contain', JSON.parse(hotelLocation));
    });
  }

  static expectDeliveryAndCollectInfoIsPresent() {
    cy.get(rentalCarCheckout.deliveryAndCollectAckCheckBox).click({
      force: true
    });
    cy.get(rentalCarCheckout.deliveryAndCollectAckCheckBoxContinue).click({
      force: true
    });
    cy.get(rentalCarCheckout.dAndCBookingInfoHeader).should('contain', 'Delivery').and('contain', 'Collection');

    cy.get(rentalCarCheckout.estimatedCost)
      .eq(0)
      .then((element) => {
        cy.task('putDataInCache', {
          key: 'estTotal',
          data: element.text().trim()
        });
      });
  }

  static searchRentalCar(pickUpLocation: string) {
    RentalCar.visitRentalCarSearch('Business');
    RentalCar.selectPickUpLocation(pickUpLocation);
    RentalCar.setPickUpAndDropOffDate();
    RentalCar.searchRentalCar();
  }

  static prepareUsers(userType: User_Type) {
    LoginPage.createNewCompanyAndLoginWithUserByType({
      providers: [Provider_Type.ALL_CAR],
      users: [userType]
    });
    RentalCarInterceptApis.interceptRentalCarApis();
  }

  static bookingWorkflow(rentalCarParams: RentalCarParams, invalidCard = false) {
    RentalCarUtility.bookRentalCar(rentalCarParams);
    if (!invalidCard) {
      RentalCarCheckout.expectBookingSuccessfully();
      Trips.validateTripDetails();
    }
  }

  static rentalCarCancelBookingWorkflow(rentalCarParams: RentalCarParams) {
    RentalCarUtility.bookRentalCar(rentalCarParams);
    RentalCarCheckout.expectBookingSuccessfully();
    Trips.validateTripDetails();
    RentalCarItinerary.cancelCar();
  }

  static prepareAmadeusCompanyAndUserCreations() {
    LoginPage.createNewCompanyAndLoginWithUserByType({
      users: [User_Type.ADMIN],
      companySuffix: '-dandc'
    });
    RentalCarInterceptApis.interceptRentalCarApis();
  }

  static prepareCompanyForFilters(locations: string, isAmadeus = false) {
    if (isAmadeus) {
      RentalCarUtility.prepareAmadeusCompanyAndUserCreations();
    } else {
      RentalCarUtility.prepareUsers(User_Type.ADMIN);
    }
    RentalCar.visitRentalCarSearch('Business');
    RentalCar.selectDropOffType('Same drop-off');
    RentalCar.selectPickUpLocation(locations);
    RentalCar.setPickUpAndDropOffDate();
    RentalCar.searchRentalCar();
  }

  static expectSelectedCarTypeIsPresent() {
    RentalCarFilters.selectCarType();
    RentalCarFilters.expectSelectedCarTypeIsPresent();
    RentalCarSearchResults.selectCar();
    RentalCarCheckout.waitToBeLoaded();
    RentalCarCheckout.setTripInfo();
    RentalCarCheckout.checkOutCar(true);
    RentalCarCheckout.expectBookingSuccessfully();
    Trips.validateTripDetails();
    Trips.expectCarTypeIsPresent();
  }
}
