import React, { useContext, useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { Link, useNavigate } from 'react-router-dom';
import produce from 'immer';
import { useFormik } from 'formik';
import SettingsContext from '../../settings-context';
import { useAppDispatch } from '../../store';
import { TravelersFormValues } from '../../types';
import { fetchPackage, setBookingType, setCurrentStep, setHasMounted, setIsFetching } from '../booking/booking-slice';
import { FLIGHT_OPTIONS_FORM_STEP, OPTIONS_FORM_STEP, SUMMARY_STEP } from '../booking/constants';
import {
  selectAgentAdressId,
  selectAgents,
  selectBookingAttributes,
  selectBookingQueryString,
  selectBookingType,
  selectCountries,
  selectHasMounted,
  selectIsFetching,
  selectIsUnavailable,
  selectStartDate,
  selectTranslations,
  selectTravelersFirstStep
} from '../booking/selectors';
import { fetchPriceDetails } from '../price-details/price-details-slice';
import { selectFormRooms, selectTravelersFormValues, setFormValues } from './travelers-form-slice';
import validateForm from './validate-form';
import SharedTravelersForm, { createInitialValuesFromRooms } from '../../../shared/booking/travelers-form';

const TravelersForm: React.FC = () => {
  const dispatch = useAppDispatch();
  const settings = useContext(SettingsContext);
  const navigate = settings.skipRouter ? () => {} : useNavigate();

  const bookingQueryString = useSelector(selectBookingQueryString);
  const startDate = useSelector(selectStartDate);
  const formRooms = useSelector(selectFormRooms);
  const bookingType = useSelector(selectBookingType);
  const agents = useSelector(selectAgents);
  const agentAdressId = useSelector(selectAgentAdressId);
  const translations = useSelector(selectTranslations);
  const travelersFirstStep = useSelector(selectTravelersFirstStep);
  const isUnavailable = useSelector(selectIsUnavailable);
  const bookingAttributes = useSelector(selectBookingAttributes);
  const isFetching = useSelector(selectIsFetching);
  const hasMounted = useSelector(selectHasMounted);
  const countries = useSelector(selectCountries);

  const useCompactForm = !!settings.travellers.compactForm && !!settings.agentAdressId;
  const showAllCountries = !!settings.travellers.showAllCountries;
  const initialValues =
    useSelector(selectTravelersFormValues) ??
    createInitialValuesFromRooms(formRooms, startDate, agentAdressId, translations.TRAVELERS_FORM.PERSON, useCompactForm);

  const [showAgentSelection, setShowAgentSelection] = useState<boolean>(!settings.agentAdressId && !settings.hideAgentSelection);

  const formik = useFormik<TravelersFormValues>({
    initialValues,
    validate: useCompactForm
      ? () => {}
      : (values) =>
          validateForm(values, settings.agentRequired, bookingType, translations, settings.travellers.formFields, settings.travellers.mainBookerFormFields),
    onSubmit: (values) => {
      dispatch(setFormValues(values));

      if (useCompactForm) {
        dispatch(fetchPriceDetails());
        if (settings.skipRouter) dispatch(setCurrentStep(SUMMARY_STEP));
        else navigate(`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.summary.pathSuffix}?${bookingQueryString}`);
        return;
      }

      dispatch(fetchPackage());
      if (settings.skipRouter) dispatch(setCurrentStep(travelersFirstStep ? FLIGHT_OPTIONS_FORM_STEP : SUMMARY_STEP));
      else
        navigate(
          `${!settings.skipBasePathInRouting ? settings.basePath : ''}${
            travelersFirstStep ? settings.flightOptions.pathSuffix : settings.summary.pathSuffix
          }?${bookingQueryString}`
        );
    }
  });

  useEffect(() => {
    dispatch(fetchPriceDetails());
  }, [dispatch]);

  useEffect(() => {
    if (!bookingAttributes?.rooms?.length || isFetching) return;
    if (!hasMounted) {
      dispatch(setHasMounted(true));
      return;
    }

    const fetchAll = async () => {
      dispatch(setIsFetching(true));
      try {
        await dispatch(fetchPackage());
        await dispatch(fetchPriceDetails());
      } finally {
        dispatch(setIsFetching(false));
      }
    };

    fetchAll();
  }, [bookingAttributes?.rooms, dispatch, hasMounted, isFetching]);

  useEffect(() => {
    if (settings.skipRouter || !travelersFirstStep) return;

    const params = new URLSearchParams(bookingQueryString);
    params.delete('rooms');
    const roomsString = formik.values.rooms
      .map((room) => {
        const adults = room.adults ? room.adults.length : 0;
        const childAges = room.children?.length ? room.children.map((child) => child.age).join(',') : '';
        return `adults:${adults},childAges:(${childAges})`;
      })
      .map((room) => `(${room})`)
      .join(',');

    const nextQuery = `${params.toString()}${params.toString() ? '&' : ''}rooms=(${roomsString})`;
    navigate(`${window.location.pathname}?${nextQuery}`, { replace: true });
  }, [formik.values.rooms, bookingQueryString, navigate, settings.skipRouter, travelersFirstStep]);

  useEffect(() => {
    if (!agents || !settings.affiliateSlug) return;
    const agent = agents.find((x) => x.affiliateSlug && x.affiliateSlug === settings.affiliateSlug);
    if (!agent) return;

    const formValues = produce(formik.values, (values) => {
      values.travelAgentId = Number(agent.id);
      values.travelAgentName = agent.name;
    });

    formik.setValues(formValues, false);
    dispatch(setFormValues(formValues));
    setShowAgentSelection(false);
  }, [agents, settings.affiliateSlug]);

  return (
    <SharedTravelersForm
      formik={formik}
      translations={translations}
      travellersSettings={settings.travellers}
      countries={countries}
      agents={agents}
      bookingType={bookingType}
      agentAdressId={agentAdressId}
      travelersFirstStep={travelersFirstStep}
      isUnavailable={isUnavailable}
      useCompactForm={useCompactForm}
      showAllCountries={showAllCountries}
      showAgentSelection={showAgentSelection}
      initialShowAgents={settings.agentRequired ?? false}
      onBookingTypeChange={(nextBookingType) => dispatch(setBookingType(nextBookingType))}
      renderPreviousButton={() =>
        !travelersFirstStep && settings.skipRouter ? (
          <button type="button" title={translations.STEPS.PREVIOUS} onClick={() => dispatch(setCurrentStep(OPTIONS_FORM_STEP))} className="cta cta--secondary">
            {translations.STEPS.PREVIOUS}
          </button>
        ) : !travelersFirstStep ? (
          <Link
            to={`${!settings.skipBasePathInRouting ? settings.basePath : ''}${settings.options.pathSuffix}?${bookingQueryString}`}
            title={translations.STEPS.PREVIOUS}
            className="cta cta--secondary">
            {translations.STEPS.PREVIOUS}
          </Link>
        ) : null
      }
    />
  );
};

export default TravelersForm;
