import { Route, Routes, useLocation, useNavigate } from 'react-router-dom';
import React, { useContext } from 'react';
import { useSelector } from 'react-redux';
import {
  getDateFromParams,
  getFlightsFromParams,
  getNumberFromParams,
  getNumbersFromParams,
  getRoomsFromParams,
  getStringFromParams
} from '../../../shared/utils/query-string-util';
import {
  fetchPackage,
  setAccommodationViewId,
  setAgentAdressId,
  setBookingAttributes,
  setBookingNumber,
  setBookingOptions,
  setBookingType,
  setCalculateDeposit,
  setGeneratePaymentUrl,
  setIsRetry,
  setIsUnavailable,
  setLanguageCode,
  setOfficeId,
  setPackage,
  setProductAttributes,
  setShowCommission,
  setSkipPayment,
  setTagIds,
  setTranslations,
  setTravelersFirstStep
} from './booking-slice';

import { isEqual, isNil } from 'lodash';
import { useEffect } from 'react';
import StepRoute from '../../components/step-route';
import SettingsContext from '../../settings-context';
import { useAppDispatch } from '../../store';
import { BookingAttributes } from '../../types';
import Confirmation from '../confirmation/confirmation';
import Error from '../error/error';
import FlightOptionsForm from '../flight-options';
import OptionsForm from '../product-options/options-form';
import RoomOptionsForm from '../room-options';
import Sidebar from '../sidebar';
import Summary from '../summary/summary';
import TravelersForm from '../travelers-form/travelers-form';
import {
  selectBookingAttributes,
  selectBookingNumber,
  selectBookingRooms,
  selectIsRetry,
  selectIsUnavailable,
  selectPackageDetails,
  selectProductAttributes,
  selectTranslations,
  selectTravelersFirstStep
} from './selectors';

interface BookingProps {
  productCode: string;
  productName: string;
  thumbnailUrl?: string;
}

const Booking: React.FC<BookingProps> = ({ productCode, productName, thumbnailUrl }) => {
  const {
    officeId,
    bookingOptions,
    basePath,
    roomOptions,
    flightOptions,
    options,
    travellers,
    summary,
    confirmation,
    error,
    showSidebarDeposit,
    showCommission,
    includeFlights,
    loaderComponent,
    skipPaymentWithAgent,
    generatePaymentUrl,
    tagIds,
    agentAdressId,
    language,
    translationFiles,
    accommodationViewId,
    isOffer,
    allowOption,
    skipBasePathInRouting
  } = useContext(SettingsContext);

  const dispatch = useAppDispatch();
  const location = useLocation();
  const navigate = useNavigate();

  const productAttributes = useSelector(selectProductAttributes);
  const bookingAttributes = useSelector(selectBookingAttributes);
  const rooms = useSelector(selectBookingRooms);
  const bookingNumber = useSelector(selectBookingNumber);
  const isRetry = useSelector(selectIsRetry);
  const packageDetails = useSelector(selectPackageDetails);
  const isUnavailable = useSelector(selectIsUnavailable);
  const translations = useSelector(selectTranslations);
  const travelersFirstStep = useSelector(selectTravelersFirstStep);

  useEffect(() => {
    return () => {
      dispatch(setPackage(undefined));
      dispatch(setBookingAttributes(undefined));
      dispatch(setProductAttributes(undefined));
    };
  }, []);

  useEffect(() => {
    dispatch(setSkipPayment(skipPaymentWithAgent ?? false));
    dispatch(setGeneratePaymentUrl(generatePaymentUrl ?? false));
  }, [skipPaymentWithAgent, generatePaymentUrl]);

  useEffect(() => {
    const params = new URLSearchParams(location.search);
    const startDate = getDateFromParams(params, 'startDate');
    const endDate = getDateFromParams(params, 'endDate');
    const catalogueId = getNumberFromParams(params, 'catalogueId') ?? getNumberFromParams(params, 'catalog');

    let rooms = getRoomsFromParams(params, 'rooms');

    if (!rooms || !rooms.length) {
      dispatch(setTravelersFirstStep(true));
      rooms = [{ adults: 2, children: 0, childAges: [] }];
    }

    if (travellers.travelersFirstStep === true) {
      dispatch(setTravelersFirstStep(true));
    }

    const flight = getFlightsFromParams(params, 'flight');
    const flightRouteId = getStringFromParams(params, 'flightRouteId');
    const vendorConfigurationId = getNumberFromParams(params, 'vendorConfigurationId');
    const allotmentName = getStringFromParams(params, 'allotmentName');
    const allotmentIds = getNumbersFromParams(params, 'allotmentId');
    const tourCode = getStringFromParams(params, 'tourCode');
    const productCode = getStringFromParams(params, 'productCode');
    const productName = getStringFromParams(params, 'productName');
    const bookingNumber = params.get('bookingNr') ?? undefined;

    if (typeof window !== 'undefined') {
      window.scrollTo(0, 0);
    }

    if (!isNil(bookingNumber)) {
      dispatch(setBookingNumber(bookingNumber));
      navigate(`${!skipBasePathInRouting ? basePath : ''}${confirmation.pathSuffix}?bookingNr=${bookingNumber}`);
    }

    const nextBookingAttrs = {
      startDate,
      endDate,
      catalogueId,
      rooms,
      flight,
      includeFlights,
      allotmentName,
      allotmentIds,
      tourCode,
      flightRouteId,
      vendorConfigurationId,
      productCode,
      productName
    } as BookingAttributes;

    if (!isNil(startDate) && !isNil(endDate) && !isNil(catalogueId) && !isNil(rooms)) {
      if (!isEqual(bookingAttributes, nextBookingAttrs)) {
        dispatch(setBookingAttributes(nextBookingAttrs));
      }
    } else {
      console.error('Failure when setting booking attributes', startDate, endDate, catalogueId, rooms);
    }
  }, [location.search, setBookingAttributes, setBookingNumber, includeFlights]);

  useEffect(() => {
    if (!productAttributes || !bookingAttributes || !isNil(bookingNumber) || !isRetry) {
      return;
    }

    // Retried
    dispatch(setIsRetry(false));

    dispatch(setIsUnavailable(false));
    // Fetch data
    const promise = dispatch(fetchPackage());
    return () => {
      promise.abort();
    };
  }, [isRetry]);

  useEffect(() => {
    const params = new URLSearchParams(location.search);
    const foundproductCode = getStringFromParams(params, 'productCode') ?? productCode;
    const foundproductName = getStringFromParams(params, 'productName') ?? productName;
    const next = {
      productCode: foundproductCode,
      productName: foundproductName
    };
    if (!isNil(foundproductCode) && !isNil(foundproductName)) {
      if (!isEqual(productAttributes, next)) {
        dispatch(setProductAttributes(next));
      }
    } else {
      console.error('Failure when setting product attributes', productCode, productName);
    }
  }, [location.search, productCode, productName, setProductAttributes]);

  const getTranslations = async () => {
    const translations = translationFiles?.map((x) =>
      fetch(x.path)
        .then((y) => y.json())
        .then((z) => ({ language: x.language, value: z }))
    );
    return translations && (await Promise.all(translations));
  };

  useEffect(() => {
    const loadTranslations = async () => {
      const translations = await getTranslations();
      dispatch(setTranslations(translations)); // Now dispatch the resolved value
    };

    loadTranslations();

    dispatch(setOfficeId(officeId));
    dispatch(setLanguageCode(language));
    dispatch(setBookingOptions(bookingOptions));
    dispatch(setCalculateDeposit(showSidebarDeposit));
    dispatch(setShowCommission(showCommission));
    if (tagIds && tagIds.length > 0) {
      dispatch(setTagIds(tagIds ?? undefined));
    }
    dispatch(setAgentAdressId(agentAdressId ?? undefined));
    if (agentAdressId && agentAdressId != 0) {
      dispatch(setBookingType('b2b'));
    }
    if (accommodationViewId && accommodationViewId != 0) {
      dispatch(setAccommodationViewId(accommodationViewId));
    }
  }, [
    officeId,
    language,
    bookingOptions,
    showSidebarDeposit,
    showCommission,
    setOfficeId,
    setLanguageCode,
    setCalculateDeposit,
    tagIds,
    agentAdressId,
    accommodationViewId
  ]);

  useEffect(() => {
    if (!productAttributes || !bookingAttributes || !rooms?.length || !isNil(bookingNumber) || !isNil(packageDetails)) {
      return;
    }
    // Fetch data
    const promise = dispatch(fetchPackage());
    return () => {
      promise.abort();
    };
  }, [productAttributes]);

  let numberIndex = 1;

  return (
    <>
      {((productAttributes && bookingAttributes && packageDetails) || bookingNumber) && (
        <div className="booking">
          <div className="booking__content">
            <div className="booking__panel">
              <Routes>
                {travelersFirstStep && (
                  <Route path="/" element={<StepRoute number={numberIndex++} title={translations.STEPS.PERSONAL_DETAILS} component={<TravelersForm />} />} />
                )}
                {!flightOptions.isHidden && flightOptions.pathSuffix && (
                  <Route
                    path={'/'}
                    element={<StepRoute number={numberIndex++} title={translations.STEPS.FLIGHT_OPTIONS} component={<FlightOptionsForm />} />}
                  />
                )}
                {!roomOptions.isHidden && roomOptions.pathSuffix && (
                  <Route
                    path={roomOptions.pathSuffix}
                    element={<StepRoute number={numberIndex++} title={translations.STEPS.ROOM_OPTIONS} component={<RoomOptionsForm />} />}
                  />
                )}
                <Route
                  path={options.pathSuffix}
                  element={<StepRoute number={numberIndex++} title={translations.STEPS.EXTRA_OPTIONS} component={<OptionsForm />} />}
                />
                {!travelersFirstStep && (
                  <Route
                    path={travellers.pathSuffix}
                    element={<StepRoute number={numberIndex++} title={translations.STEPS.PERSONAL_DETAILS} component={<TravelersForm />} />}
                  />
                )}
                <Route path={summary.pathSuffix} element={<StepRoute number={numberIndex++} title={translations.STEPS.SUMMARY} component={<Summary />} />} />
                <Route
                  path={confirmation.pathSuffix}
                  element={<StepRoute number={numberIndex++} title={translations.STEPS.CONFIRMATION} component={<Confirmation />} />}
                />
                <Route path={error.pathSuffix} element={<StepRoute number={numberIndex++} title={translations.STEPS.ERROR} component={<Error />} />} />
              </Routes>
            </div>
            <div className="backdrop" id="backdrop"></div>
            <Sidebar productName={productName} thumbnailUrl={thumbnailUrl} />
          </div>
        </div>
      )}

      {!packageDetails && !bookingNumber && !isUnavailable && (
        <div className="booking">
          <div className="booking__loader">
            {loaderComponent}
            <p className="booking__loader-text">
              {allowOption ? translations.MAIN.PREPARING_DOSSIER : isOffer ? translations.MAIN.PREPARING_OFFER : translations.MAIN.PREPARING_BOOKING}
            </p>
          </div>
        </div>
      )}
      {isUnavailable && !travelersFirstStep && (
        <div className="booking">
          <div className="booking__loader">
            <p className="booking__loader-text">{translations.MAIN.PRODUCT_UNAVAILABLE}</p>
          </div>
        </div>
      )}
    </>
  );
};

export default Booking;
