import { Logs, Timeouts } from '@utility-lib/index';
import { Directions } from './booking';

export const chatBookingSelectors = {
  chatToggleButton: '[data-testid="ta-chat-toggle-button"]',
  chatMessagesViewLoader: '#chat-body [data-testid="Loader"]',
  bookTravelButton: '#chat-body [data-testid="Book travel"]',
  bookSpecificTravelButton: (travelType: string) =>
    `#chat-body [data-testid="${travelType}"]`,
  airportInput: (direction: Directions) => `#chat-body input[placeholder="${direction}"]`,
  calendarNextMonthButton: '#chat-body .react-calendar__navigation__next-button',
  calendarDayButtons: '#chat-body .react-calendar__month-view__days',
  disabledCalendarDayButton:
    ':not(.react-calendar__month-view__days__day--neighboringMonth)',
  calendar: '#chat-body .react-calendar',
  letsGoButton: '#chat-body [data-testid="Let\'s go!"]',
  airportsFromAutocomplete: (airports: string) =>
    `#chat-body [data-testid="${airports}"]`,
  formFields: '#chat-body [data-testid="micro-form-label"]',
  startChatButton: '#chat-body [data-testid="new-chat-button"]',
  endChatButton: '#chat-body [data-testid="Nav__closeButton"]',
  leaveChatButtons: '[data-testid="leave-chat-confirmation"] [data-testid="btn-group"]',
  flightCards: '#chat-body [data-testid="new-flight-info"]',
  flightChangeCards: '.swiper-slide > div',
  flightCardsList: '[data-testid="new-flight-search-swiper-swiper"]',
  chatButton: '#chat-body button',
  paginatorNextButton:
    '#chat-body [data-testid="swiper-paginator"] [data-testid="right-chevron"]',
  chatView: '[data-role="ta-chat-messages-view"]',
  getTextsAfterSelectingBookingDetails:
    '[class*="messageAnim-enter"] [data-testid="micro-form-label"]',
  chatMsgInput: '[data-role="ta-chat-message-input"]',
  chatButtonReplyToAva: '[data-testid="ChatButton"]',
  needHelpByChat: '[data-testid="needHelpByChat"]',
  chatBody: '[data-testid="messages_scroll"] > div',
  getChatMsgBody: '[data-role="ta-chat-message-item-body"] P',
  getMsg: '[data-testid="messageItem"] p',
  chatLogo: '[data-testid="entry__logo"]',
  replyToAva: (replyMsg: string) =>
    `[data-testid="ChatButton"] [data-testid*="${replyMsg}"]`,
  chatInvoiceElement:
    '[data-role="ta-chat-message-item-body"] div > div:nth-child(2) > a',
  labelMessage: '[data-testid="labelMessage"]'
};

export enum TravelType {
  FLIGHT = 'Flight',
  HOTEL = 'Hotel',
  CAR = 'Car',
  TRAIN = 'Train'
}

export class ChatBox {
  static openChatWithAva() {
    cy.allure().logStep('Open chat with Ava');
    this.openChat();
    this.startNewChatWithAva();
  }

  static getCheckInCheckOutDates() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(chatBookingSelectors.getTextsAfterSelectingBookingDetails)
      .contains('Dates')
      .siblings()
      .invoke('text')
      .then((dateRange) => {
        cy.log(dateRange);
        cy.task('putDataInCache', {
          key: 'chatBoxDateRange',
          data: dateRange
        });
      });
    cy.allure().logStep(`Get check-in and check-out dates`);
  }

  static newChatButtonShouldVisible() {
    cy.get(chatBookingSelectors.startChatButton).should('be.visible');
    cy.allure().logStep('New chat button is visible');
  }

  static startANewChatOrContinue() {
    this.openChat();
    cy.get(chatBookingSelectors.chatButtonReplyToAva).then(($buttons) => {
      if (!$buttons.length) {
        ChatBox.startNewChatWithAva();
      }
    });
  }

  static openChat() {
    cy.allure().logStep('Open chat');
    cy.get(chatBookingSelectors.chatToggleButton).should('be.visible').click();
    this.waitUntilChatLoaderDisappears();
  }

  static closeChat() {
    cy.allure().logStep('Close chat');
    cy.get(chatBookingSelectors.endChatButton).should('be.visible').click();
  }

  static confirmCloseChat() {
    cy.allure().logStep('Confirm close chat');
    cy.get(chatBookingSelectors.leaveChatButtons).contains('Yes, end chat').click();
    cy.get(chatBookingSelectors.labelMessage).should('contain.text', 'Chat ended');
    cy.allure().logStep(`Chat ended.`);
  }

  static denyCloseChat() {
    cy.allure().logStep('Deny close chat');
    cy.get(chatBookingSelectors.leaveChatButtons).contains('Continue chatting').click();
  }

  static waitUntilChatLoaderDisappears() {
    cy.allure().logStep('Wait until chat loader disappears');
    cy.get(
      chatBookingSelectors.chatMessagesViewLoader,
      Timeouts.MEDIUM_TIMEOUT_60_SEC
    ).should('not.exist');
  }

  static waitUntilAvaStopTyping() {
    cy.allure().logStep('Wait until Ava stop typing');
    cy.get(chatBookingSelectors.chatBody, Timeouts.MAX_TIMEOUT_120_SEC)
      .contains('Ava is typing')
      .should('not.be.visible');
  }

  static startNewChatWithAva() {
    cy.allure().logStep('Start new chat with Ava');
    cy.wait(['@waitForInitChatChannel', '@waitForAgentToCatiInProgress']);
    this.waitUntilChatLoaderDisappears();
  }

  static selectBookTravelFlow(travelType: TravelType) {
    cy.allure().logStep(`Select ${travelType} travel flow`);
    cy.get(chatBookingSelectors.bookTravelButton).click();
    cy.get(chatBookingSelectors.bookSpecificTravelButton(travelType)).click();
  }

  static getHotelLocationText() {
    cy.get(chatBookingSelectors.getTextsAfterSelectingBookingDetails)
      .contains(Directions.HOTEL_LOCATION)
      .siblings()
      .invoke('text')
      .then((chatLocationInput) => {
        cy.log(chatLocationInput);
        cy.task('putDataInCache', {
          key: 'locationText',
          data: chatLocationInput
        });
      });
    cy.allure().logStep(`Get hotel location text`);
  }

  static selectMsgYouWannaSendBackToAva(conversation: string, fallback?: string) {
    if (!fallback) {
      cy.get(chatBookingSelectors.replyToAva(conversation)).should('be.visible').click();
      cy.allure().logStep(`Select message you wanna send back to Ava: ${conversation}`);

      return;
    }

    cy.get(chatBookingSelectors.chatButtonReplyToAva)
      .then(($buttons) => {
        if ($buttons.eq(1).text() === conversation) {
          return [conversation, fallback];
        }

        return [fallback];
      })
      .then((responses) => {
        responses.forEach((response) => {
          ChatBox.selectMsgYouWannaSendBackToAva(response);
        });
      });
  }

  static typeMsgToAva(typeMsg: string) {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(chatBookingSelectors.chatMsgInput).type(`${typeMsg}{enter}`);
    cy.allure().logStep(`Type message to Ava: ${typeMsg}`);
  }

  static verifyIfMsgInputDisplayed() {
    cy.allure().logStep('Verify if message input is not displayed');
    cy.get(chatBookingSelectors.chatMsgInput).should('exist');
  }

  static verifyIfMsgInputNotDisplayed() {
    cy.allure().logStep('Verify if message input is not displayed');
    cy.get(chatBookingSelectors.chatMsgInput).should('not.exist');
  }

  static getHotelDetailForChange() {
    cy.contains(chatBookingSelectors.getMsg, /Hotel in/)
      .invoke('text')
      .then((text: any) => {
        cy.log('Booked hotel details' + text);
        this.typeMsgToAva(
          `i would like to change hotel, here's the detail ${text} would like different hotel on same dates`
        );
        this.confirmationMsg();
      });
    cy.allure().logStep(`Get hotel detail for change`);
  }

  static changeHotel() {
    this.waitUntilChatLoaderDisappears();
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(chatBookingSelectors.chatButtonReplyToAva).then(($elements) => {
      cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
      if ($elements.text().includes('Make a second booking')) {
        this.selectMsgYouWannaSendBackToAva('Make a second booking');
      } else if ($elements.text().includes('Continue to change')) {
        cy.contains('Continue to change').click();
      }
    });
    cy.allure().logStep(`Change hotel`);
  }

  static confirmationMsg() {
    cy.get(chatBookingSelectors.getMsg).then(($element) => {
      if (
        $element
          .text()
          .includes('Just to confirm, you want to change your hotel booking in ')
      ) {
        this.typeMsgToAva('Far from my destination, so please change it');
      }
    });
    cy.allure().logStep(`Confirmation message`);
  }

  static changeHotelConversation() {
    cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
    cy.get(chatBookingSelectors.getMsg).then(($elements) => {
      if ($elements.text().includes('What would you like to do?')) {
        this.getHotelDetailForChange();
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        this.waitUntilChatLoaderDisappears();
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        this.confirmationMsg();
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        this.waitUntilChatLoaderDisappears();
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        this.selectMsgToReply();
      }
    });
    cy.allure().logStep(`Change hotel conversation`);
  }

  static selectMsgToReply() {
    cy.get(chatBookingSelectors.chatButtonReplyToAva).then(($elements) => {
      if ($elements.length > 0) {
        cy.log('wait for chat button to appear');
        cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
        this.changeHotel();
      } else {
        cy.get(chatBookingSelectors.chatMsgInput)
          .its('length')
          .then((length) => {
            if (length > 0) {
              cy.log('wait for chat message input to appear');
              cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
              this.typeMsgToAva('Yes');
              cy.log('send msg to ava');
              cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
            } else {
              cy.wait(Timeouts.SHORT_TIMEOUT_3_SEC.timeout);
            }
          });
      }
    });
    cy.allure().logStep(`Select message to reply`);
  }

  static replyToAva(replyMsg: string) {
    cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
    cy.get(chatBookingSelectors.replyToAva(replyMsg)).should('be.visible').click();
    cy.allure().logStep(`Reply to Ava: ${replyMsg}`);
  }

  static selectBooking(replyMsg: string, index: number) {
    cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
    cy.get(chatBookingSelectors.replyToAva(replyMsg))
      .should('be.visible')
      .eq(index)
      .click();
    cy.allure().logStep(`Select ${replyMsg} booking number: ${index}`);
  }

  static expectFurtherAvaConnectToAgent(replyMsg: string) {
    cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
    cy.contains('Continue to change').should('not.exist');
    cy.get(`[data-testid="${replyMsg}"]`).should('not.exist');
    cy.contains('Let me get an agent to help.').should('be.visible');
    cy.allure().logStep(`Ava connect to agent`);
  }

  static needHelpByChat() {
    cy.get(chatBookingSelectors.chatLogo).should('be.visible');
    cy.get(chatBookingSelectors.needHelpByChat).should('be.visible').click();
    cy.allure().logStep('Need help by chat');
  }

  static readAvaMsgAndSelectReply(weGotMsgFromAva: string, weReplied: string) {
    cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
    ChatBox.waitUntilAvaStopTyping();
    cy.get(chatBookingSelectors.getChatMsgBody).then(($elements) => {
      if ($elements.text().includes(weGotMsgFromAva)) {
        ChatBox.replyToAva(`${weReplied}`);
        cy.allure().logStep(`Message received from Ava: ${weGotMsgFromAva}`);
      }
    });
    cy.allure().logStep(`Message sent to Ava: ${weReplied}`);
  }

  static readAvaMsgAndTypeReply(weGotMsgFromAva: string, weReplied: string) {
    cy.wait(Timeouts.MEDIUM_TIMEOUT_10_SEC.timeout);
    ChatBox.waitUntilAvaStopTyping();
    cy.get(chatBookingSelectors.getChatMsgBody).then(($elements) => {
      cy.allure().logStep(
        `Checking if message received from Ava contains: ${weGotMsgFromAva}`
      );
      if ($elements.text().includes(weGotMsgFromAva)) {
        ChatBox.typeMsgToAva(`${weReplied}`);
        cy.allure().logStep(`Message received from Ava: ${weGotMsgFromAva}`);
      }
    });
    cy.allure().logStep(`Message sent to Ava: ${weReplied}`);
  }

  static expectMsgReceivedFromAva(weGotMsgFromAva: string) {
    cy.wait(Timeouts.SHORT_TIMEOUT_5_SEC.timeout);
    cy.get(chatBookingSelectors.getChatMsgBody).should(
      'contain.text',
      `${weGotMsgFromAva}`
    );
    cy.allure().logStep(`Message received from Ava: ${weGotMsgFromAva}`);
  }

  static validateFlightItinerary(locations: string[]) {
    cy.allure().logStep('Validating flight itinerary.');
    cy.task('getDataFromCache', 'selectedCheckInDate').then(
      (selectedCheckInDate: any) => {
        cy.task('getDataFromCache', 'selectedCheckoutDate').then(
          (selectedCheckoutDate: any) => {
            const checkInDate = new Date(selectedCheckInDate);
            const checkoutDate = new Date(selectedCheckoutDate);
            const checkinDateToValidation = checkInDate.toDateString().substring(4);
            const checkoutDateToValidation = checkoutDate.toDateString().substring(4);
            const fromLocation = locations[0].substring(0, 3);
            const toLocation = locations[1].substring(0, 3);
            this.expectMsgReceivedFromAva(
              `Flight from ${fromLocation} to ${toLocation} on ${checkinDateToValidation}. Returning on ${checkoutDateToValidation}`
            );
          }
        );
      }
    );
  }

  static checkIfInvoicePresent() {
    cy.allure().logStep('Checking if an invoice is present.');
    cy.get(chatBookingSelectors.chatInvoiceElement).should('be.visible');
  }

  static validateInvoiceMsgText(text: string) {
    cy.allure().logStep(`Validating if invoice message text is equal "${text}".`);
    cy.get(chatBookingSelectors.chatInvoiceElement)
      .parents()
      .should('contain.text', text);
  }
}
