import {
  RentalCar,
  RentalCarSearchResults,
  RentalCarFilters,
  RentalCarCheckout,
  filtersSelector,
  LocationUtility
} from '@rentalCar-lib/index';
import { RentalCarDropOffType, RentalCarLocationType } from './rental_car_utility';
import { Random } from '@utility-lib/random';
import { Timeouts, TripTileType } from '@utility-lib/constants';
import {
  hotelsEU,
  hotelsUS,
  office,
  rentalCarGeneralLocation,
  airportLocations,
  addressUS
} from '@fixtures/shared/locations';
import { rentalCarSearchResultSelector } from '@rentalCar-lib/search_results';

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

export class RetryRentalCarModel {
  static getLocationDescription(params: LocationParams) {
    const { tripTileType, dropOffType, outOfPolicy, rentalCarLocationType, directBill, policyType } = params;
    {
      const selectPickUpLocation = (location: string) => {
        RentalCar.selectPickUpLocation(location);
      };

      const selectDropOffLocation = (location: string) => {
        RentalCar.selectDropOffLocation(location);
      };

      const getRandomLocation = (locations: string[]) => {
        return Random.getRandomValueFromArray(locations);
      };

      const getRandomDifferentLocation = (locations: string[], currentLocation: string) => {
        return Random.getRandomValueFromArray(locations.filter((location) => location !== currentLocation));
      };

      const handleLocationType = (locationType: RentalCarLocationType, locations: string[]) => {
        const pickUpLocation = getRandomLocation(locations);
        const dropOffLocation = getRandomDifferentLocation(locations, pickUpLocation);

        selectPickUpLocation(pickUpLocation);

        if (dropOffType === RentalCarDropOffType.differentDropOff) {
          selectDropOffLocation(dropOffLocation);
        } else {
          selectDropOffLocation(pickUpLocation);
        }
      };

      switch (rentalCarLocationType) {
        case RentalCarLocationType.airport:
          handleLocationType(RentalCarLocationType.airport, airportLocations);
          break;

        case RentalCarLocationType.office:
          handleLocationType(RentalCarLocationType.office, office);
          break;

        case RentalCarLocationType.hotelUS:
          handleLocationType(RentalCarLocationType.hotelUS, hotelsUS);
          break;

        case RentalCarLocationType.hotelEU:
          handleLocationType(RentalCarLocationType.hotelEU, hotelsEU);
          break;

        case RentalCarLocationType.general:
          handleLocationType(RentalCarLocationType.general, rentalCarGeneralLocation);
          break;

        default:
          throw new Error('Invalid location type.');
      }

      RentalCarSearchResults.searchCarFromSearchResults();

      if (dropOffType === RentalCarDropOffType.deliverAndCollect) {
        cy.get(rentalCarSearchResultSelector.searchLoader, { timeout: 30000 }).should('not.exist');
        RentalCarFilters.selectRentalCarOperator('Sixt');
      }

      if (outOfPolicy === 'Yes' && policyType === 'class') {
        RentalCarFilters.selectCarType();
      }
      cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
      RentalCarFilters.selectAgency();

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

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

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

      if (dropOffType !== RentalCarDropOffType.deliverAndCollect || !directBill) {
        RentalCarCheckout.setAcknowledgement();
      }
    }
  }

  static searchAndSelectCarOperator(rentalCarOperator: string, retryCount = 4) {
    const getRandomDifferentLocation = (locations: string[], currentLocation: string) => {
      return Random.getRandomValueFromArray(locations.filter((location) => location !== currentLocation));
    };

    const pickUpLocation = LocationUtility.getRentalCarAirportUS();
    let currentLocation = pickUpLocation;

    const selectPickUpLocation = (location: string) => {
      RentalCar.selectPickUpLocation(location);
    };

    const selectDropOffLocation = (location: string) => {
      RentalCar.selectDropOffLocation(location);
    };

    const handleRetry = () => {
      if (retryCount > 0) {
        cy.log(`National is not available, retrying... Retries left: ${retryCount}`);
        cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);

        currentLocation = getRandomDifferentLocation(airportLocations, currentLocation);
        selectPickUpLocation(currentLocation);
        selectDropOffLocation(currentLocation);

        RentalCarSearchResults.searchCarFromSearchResults();
        cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
        RentalCarFilters.selectAgency();
        this.searchAndSelectCarOperator(rentalCarOperator, retryCount - 1);
      } else {
        throw new Error(`*** ${rentalCarOperator} *** is not available after 4 retries`);
      }
    };

    cy.get(rentalCarSearchResultSelector.agencyFilter).click({ force: true });
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);

    cy.get('body').then(($body) => {
      if ($body.text().includes(rentalCarOperator)) {
        cy.get(filtersSelector.carOperatorCheckbox).contains(`${rentalCarOperator}`).click({ timeout: 10000 });
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        cy.get(rentalCarSearchResultSelector.agencyFilter).click({ force: true });
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
      } else {
        handleRetry();
      }
    });
  }
}
