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

import {
  AirlineBookingPackageOption,
  AirportBookingPackageOption,
  BookingAirlineGroup,
  BookingAirportGroup,
  BookingOptionGroup,
  BookingOptionPax,
  BookingOptionUnit,
  BookingPackageFlight,
  Pax,
  PerBookingPackageOption,
} from "@qite/tide-client/build/types";
import { Link, navigate } from "@reach/router";
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,
  TRAVELERS_FORM_STEP,
} from "../booking/constants";
import {
  selectAvailabilities,
  selectBookingPackagePax,
  selectBookingQueryString,
  selectIsFetchingProductOptions,
  selectPackageAirlineGroups,
  selectPackageAirportGroups,
  selectPackageDetails,
  selectPackageGroups,
  selectPackageOptionPax,
  selectPackageOptionUnits,
  selectPackageRooms,
  selectPackageTags,
  selectRequestRooms,
  selectTagIds,
  selectTranslations,
} 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";

interface OptionsFormProps {}

const OptionsForm: React.FC<OptionsFormProps> = () => {
  const settings = useContext(SettingsContext);
  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);

  // ROOMS
  const 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) {
      dispatch(setCurrentStep(TRAVELERS_FORM_STEP));
    } else {
      navigate(
        `${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.basePath}${settings.flightOptions.pathSuffix}?${bookingQueryString}`
    : `${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}
                                  />
                                ))}
                            </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;
