import React, { useContext, useEffect } from 'react';

import {
  AirlineBookingPackageOption,
  AirportBookingPackageOption,
  BookingAirlineGroup,
  BookingAirportGroup,
  BookingOptionGroup,
  BookingOptionPax,
  BookingOptionUnit,
  BookingPackageFlight,
  Pax,
  PerBookingPackageOption
} from '@qite/tide-client/build/types';
import { isEmpty } from 'lodash';
import { useSelector } from 'react-redux';
import { buildClassName } from '../../../shared/utils/class-util';
import SettingsContext from '../../settings-context';
import { useAppDispatch } from '../../store';
import {
  setCurrentStep,
  setPackage,
  setPackageAirlineGroups,
  setPackageAirportGroups,
  setPackageGroups,
  setPackageOptionPax,
  setPackageOptionUnits,
  setPackageRooms,
  setTagIds
} from '../booking/booking-slice';
import { FLIGHT_OPTIONS_FORM_STEP, ROOM_OPTIONS_FORM_STEP, SUMMARY_STEP, TRAVELERS_FORM_STEP } from '../booking/constants';
import {
  selectAvailabilities,
  selectBookingPackagePax,
  selectBookingQueryString,
  selectIncludedServiceTypes,
  selectIsFetchingProductOptions,
  selectPackageAirlineGroups,
  selectPackageAirportGroups,
  selectPackageDetails,
  selectPackageGroups,
  selectPackageOptionPax,
  selectPackageOptionUnits,
  selectPackageRooms,
  selectPackageTags,
  selectRequestRooms,
  selectTagIds,
  selectTranslations,
  selectTravelersFirstStep
} from '../booking/selectors';
import { fetchPriceDetails } from '../price-details/price-details-slice';
import { updatePackageRooms } from '../room-options/room-utils';
import NoOptions from './no-options';
import OptionBookingAirlineGroup from './option-booking-airline-group';
import OptionBookingGroup from './option-booking-group';
import OptionPaxCard from './option-pax-card';
import OptionRoom from './option-room';
import OptionUnitsCard from './option-units-card';
import PrintOfferButton from '../../components/print-offer-button';
import { Link, useNavigate } from 'react-router-dom';

interface OptionsFormProps {}

const OptionsForm: React.FC<OptionsFormProps> = () => {
  const settings = useContext(SettingsContext);
  const navigate = settings.skipRouter ? () => {} : useNavigate();
  const { token } = settings;
  const translations = useSelector(selectTranslations);
  const dispatch = useAppDispatch();
  const packageDetails = useSelector(selectPackageDetails);
  const requestRooms = useSelector(selectRequestRooms);
  const requestRoomsPax = requestRooms?.flatMap((x) => x.pax);
  const bookingQueryString = useSelector(selectBookingQueryString);
  const isLoading = useSelector(selectIsFetchingProductOptions);

  const groups = useSelector(selectPackageGroups);
  const airlineGroups = useSelector(selectPackageAirlineGroups);
  const airportGroups = useSelector(selectPackageAirportGroups);
  const optionUnits = useSelector(selectPackageOptionUnits);
  const optionPax = useSelector(selectPackageOptionPax);
  const availabilities = useSelector(selectAvailabilities);
  const includedServiceTypes = useSelector(selectIncludedServiceTypes);
  const travelersFirstStep = useSelector(selectTravelersFirstStep);

  // ROOMS
  const showRoomOptions = settings?.options?.showRoomOptions ?? settings.roomOptions.isHidden;
  const packageRooms = useSelector(selectPackageRooms);
  const pax = useSelector(selectBookingPackagePax);

  const getRoomPax = (index: number) => {
    var room = requestRooms?.find((x) => x.index == index);
    var bookingPackagePax = pax.filter((x) => room?.pax.some((y) => y.id == x.id));
    return bookingPackagePax.length > 0 ? bookingPackagePax : room?.pax ?? [];
  };

  const handleOnRoomChange = (index: number, accommodationCode: string, regimeCode: string | null) => {
    if (!packageRooms) return;

    const updatedPackageRooms = updatePackageRooms(packageRooms, index, accommodationCode, regimeCode, availabilities!);

    dispatch(setPackageRooms(updatedPackageRooms));
    dispatch(fetchPriceDetails());
  };

  const getPax = () => {
    if (!packageDetails) return undefined;
    const selectedOption = packageDetails.options.find((o) => o.isSelected) ?? packageDetails.options[0];
    return selectedOption?.requestRooms.flatMap((r) => r.pax) as Pax[];
  };

  // TAGS
  const packageTags = settings.hideTags ? [] : useSelector(selectPackageTags);
  let tagIds = useSelector(selectTagIds) ?? [];

  const handleSubmit: React.FormEventHandler<HTMLFormElement> = (e) => {
    if (settings.skipRouter) {
      if (travelersFirstStep) {
        dispatch(setCurrentStep(SUMMARY_STEP));
      } else {
        dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
      }
    } else {
      if (travelersFirstStep) {
        navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.summary.pathSuffix}?${bookingQueryString}`);
      } else {
        navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.travellers.pathSuffix}?${bookingQueryString}`);
      }
    }

    e.preventDefault();
  };

  const handleOnPaxChange = (pax: BookingOptionPax[]) => {
    dispatch(setPackageOptionPax(pax));
    dispatch(fetchPriceDetails());
  };

  const handleOnUnitsChange = (units: BookingOptionUnit[]) => {
    dispatch(setPackageOptionUnits(units));
    dispatch(fetchPriceDetails());
  };

  const handleOnGroupChange = (group: BookingOptionGroup<PerBookingPackageOption>) => {
    if (groups) {
      const updatedGroups = groups?.map((g) => (g.name === group.name ? group : g));

      dispatch(setPackageGroups(updatedGroups));
      dispatch(fetchPriceDetails());
    }
  };

  const handleOnAirlineGroupChange = (group: BookingAirlineGroup<AirlineBookingPackageOption>) => {
    if (airlineGroups) {
      const updatedGroups = airlineGroups.map((g) => (g.label === group.label ? group : g));

      dispatch(setPackageAirlineGroups(updatedGroups));
      dispatch(fetchPriceDetails());
    }
  };

  const handleOnAirportGroupChange = (group: BookingAirportGroup<AirportBookingPackageOption>) => {
    if (airportGroups) {
      const updatedGroups = airportGroups.map((g) => (g.label === group.label ? group : g));

      dispatch(setPackageAirportGroups(updatedGroups));
      dispatch(fetchPriceDetails());
    }
  };

  const handleOnTagChange = (id: number, checked: boolean) => {
    let updatedTags = [...tagIds];
    if (checked) {
      if (!updatedTags?.includes(id)) {
        updatedTags?.push(id);
      }
    } else {
      updatedTags = updatedTags?.filter((x) => x != id);
    }

    dispatch(setTagIds(updatedTags));
    dispatch(fetchPriceDetails());
  };

  useEffect(() => {
    if (packageDetails && settings.roomOptions.isHidden && settings.flightOptions.isHidden) {
      const params = new URLSearchParams(location.search);

      const outwardFlight = params.get('outwardflight') ?? undefined;
      const returnFlight = params.get('returnflight') ?? undefined;
      if (outwardFlight && returnFlight) {
        const desiredOutwardFlight = packageDetails.outwardFlights.find((x) => x.entryLineGuid == outwardFlight);
        const desiredReturnFlight = packageDetails.returnFlights.find((x) => x.entryLineGuid == returnFlight);
        if (desiredOutwardFlight && desiredReturnFlight) {
          dispatch(
            setPackage({
              ...packageDetails,
              outwardFlights: packageDetails.outwardFlights.map((flight) => {
                return {
                  ...flight,
                  isSelected: flight.entryLineGuid == desiredOutwardFlight.entryLineGuid ? true : false
                } as BookingPackageFlight;
              }),
              returnFlights: packageDetails.returnFlights.map((flight) => {
                return {
                  ...flight,
                  isSelected: flight.entryLineGuid == desiredReturnFlight.entryLineGuid ? true : false
                } as BookingPackageFlight;
              })
            })
          );
        }
      }
    }
    dispatch(fetchPriceDetails());
  }, []);

  const goPrevious = () => {
    if (settings.roomOptions.isHidden) {
      dispatch(setCurrentStep(FLIGHT_OPTIONS_FORM_STEP));
    } else {
      dispatch(setCurrentStep(ROOM_OPTIONS_FORM_STEP));
    }
  };

  const previousUrl = settings.roomOptions.isHidden
    ? `${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.flightOptions.pathSuffix}?${bookingQueryString}`
    : `${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.roomOptions.pathSuffix}?${bookingQueryString}`;
  const hasPrevious = !settings.roomOptions.isHidden || !settings.flightOptions.isHidden;
  const showPackageTagsOrRoomoptions = showRoomOptions || (packageTags && !isEmpty(packageTags));

  return (
    <>
      <form className="form" name="booking--options" id="booking--options" noValidate onSubmit={handleSubmit}>
        {isLoading && settings.loaderComponent}
        {!isLoading && (
          <div className="form__region">
            {showPackageTagsOrRoomoptions && (
              <div className="form__group">
                <div className="booking-card">
                  <div className="booking-card__body">
                    <div className={buildClassName(['booking-card__group', 'booking-card__group--package'])}>
                      {showRoomOptions && <span className="booking-card__tag">{translations.OPTIONS_FORM.PACKAGE}</span>}
                      <div className="booking-card__group-body">
                        {showRoomOptions && (
                          <table className="table table--striped">
                            <tbody>
                              {packageRooms &&
                                packageRooms.map((room) => (
                                  <OptionRoom
                                    key={room.index}
                                    packageRoom={room}
                                    pax={getRoomPax(room.index)}
                                    optionPax={optionPax}
                                    onRoomChange={handleOnRoomChange}
                                    includedServiceTypes={includedServiceTypes}
                                  />
                                ))}
                            </tbody>
                          </table>
                        )}
                        {packageTags && !isEmpty(packageTags) && (
                          <div className="booking-card__tag-translations">
                            {packageTags.map((tag, index) => (
                              <label key={index} htmlFor={`tag-translation-${index}-${tag.title}`} className="checkbox__label tag-translation">
                                <div className="tag-translation-input__container">
                                  <input
                                    type="checkbox"
                                    id={`tag-translation-${index}-${tag.title}`}
                                    name={`tag-translation-${index}-${tag.title}`}
                                    className="checkbox__input"
                                    checked={tagIds?.includes(tag.id)}
                                    onChange={(e) => handleOnTagChange(tag.id, e.target.checked)}
                                  />
                                </div>
                                <span className="tag-translation__title">{tag.title}</span>
                                &nbsp;
                                <span className="tag-translation__description">{tag.description}</span>
                              </label>
                            ))}
                          </div>
                        )}
                      </div>
                    </div>
                  </div>
                </div>
              </div>
            )}
            {optionUnits && !isEmpty(optionUnits) && (
              <div className="form__group">
                <div className="booking-card">
                  <div className="booking-card__header">
                    <h2 className="booking-card__header-heading">{translations.OPTIONS_FORM.PER_UNIT_TITLE}</h2>
                  </div>
                  <div className="booking-card__body">
                    <OptionUnitsCard units={optionUnits} onUnitsChange={handleOnUnitsChange} />
                  </div>
                </div>
              </div>
            )}

            {optionPax && !isEmpty(optionPax) && (
              <div className="form__group">
                <div className="booking-card">
                  <div className="booking-card__header">
                    <h2 className="booking-card__header-heading">{translations.OPTIONS_FORM.PER_PAX_TITLE}</h2>
                  </div>
                  <div className="booking-card__body">
                    <OptionPaxCard pax={optionPax} onPaxChange={handleOnPaxChange} requestRoomsPax={requestRoomsPax} />
                  </div>
                </div>
              </div>
            )}

            {groups && !isEmpty(groups) && (
              <div className="form__group">
                <div className="booking-card">
                  <div className="booking-card__header">
                    <h2 className="booking-card__header-heading">{translations.OPTIONS_FORM.PER_BOOKING_TITLE}</h2>
                  </div>
                  <div className="booking-card__body">
                    <div className="booking-card__group booking-card__group--active">
                      {groups.map((group, i) => (
                        <OptionBookingGroup
                          key={`${group.name}_${i}`}
                          group={group}
                          firstClassName={'booking-card__group-body'}
                          secondClassName={'booking-card__group-heading'}
                          parentId={`booking_${group.name}`}
                          onGroupChange={handleOnGroupChange}
                        />
                      ))}
                      {airlineGroups?.map((group, i) => (
                        <OptionBookingAirlineGroup key={`${group.label}_${i}`} airGroup={group} onGroupChange={handleOnAirlineGroupChange} />
                      ))}
                      {airportGroups?.map((group, i) => (
                        <OptionBookingAirlineGroup key={`${group.label}_${i}`} airGroup={group} onGroupChange={handleOnAirportGroupChange} />
                      ))}
                    </div>
                  </div>
                </div>
              </div>
            )}

            {isEmpty(groups) && isEmpty(optionUnits) && isEmpty(optionPax) && <NoOptions />}
          </div>
        )}
        <div className="booking__navigator">
          {hasPrevious && (
            <>
              {settings.skipRouter ? (
                <button type="button" title={translations.STEPS.PREVIOUS} onClick={() => goPrevious()} className="cta cta--secondary">
                  {translations.STEPS.PREVIOUS}
                </button>
              ) : (
                <Link to={previousUrl} title={translations.STEPS.PREVIOUS} className="cta cta--secondary">
                  {translations.STEPS.PREVIOUS}
                </Link>
              )}
            </>
          )}
          {token && settings.options.reportPrintActionId && (
            <PrintOfferButton
              bookingPackage={packageDetails}
              getPax={getPax}
              tagIds={tagIds}
              printActionId={settings.options.reportPrintActionId}
              labelIdle={translations.PRINT_OFFER_BUTTON.LABEL_IDLE}
              labelCreating={translations.PRINT_OFFER_BUTTON.LABEL_CREATING}
              labelPrinting={translations.PRINT_OFFER_BUTTON.LABEL_PRINTING}
              className="cta spinner-button"
            />
          )}
          <button type="submit" title={translations.STEPS.NEXT} disabled={isLoading} className={buildClassName(['cta', isLoading && 'cta--disabled'])}>
            {translations.STEPS.NEXT}
          </button>
        </div>
      </form>
    </>
  );
};

export default OptionsForm;
