import React, { useContext, useEffect, useMemo, useState } from 'react';
import { getTranslations } from '../../../shared/utils/localization-util';
import { SearchResultsRootState } from '../../store/search-results-store';
import { useDispatch, useSelector } from 'react-redux';
import SearchResultsConfigurationContext from '../../search-results-configuration-context';
import BookingPanel from '../../../shared/booking/booking-panel';
import StepIndicators from '../../../shared/booking/step-indicators';
import WLSidebar from './wl-sidebar';
import { SearchSeed } from '../../types';
import SharedTravelersForm, {
  applyTravelersFormValuesToEditablePackagingEntry,
  createInitialValuesFromEditablePackagingEntry,
  SharedTravelersSettings
} from '../../../shared/booking/travelers-form';
import { useFormik } from 'formik';
import { TravelersFormValues } from '../../../booking-wizard/types';
import { setBookingNumber, setCurrentStep, setEditablePackagingEntry } from '../../store/search-results-slice';
import validateForm from '../../../booking-wizard/features/travelers-form/validate-form';
import {
  bookPackagingEntry,
  CountryItem,
  getCountries,
  PackagingAccommodationResponse,
  PackagingEntry,
  PackagingRequestBase,
  TideClientConfig
} from '@qite/tide-client';
import SharedSummary from '../../../shared/booking/summary';
import { renderEditablePackagingEntrySummaryOptions } from '../../../shared/utils/booking-summary';
import SharedConfirmation from '../../../shared/booking/shared-confirmation';
import Spinner from '../spinner/spinner';

interface BookPackagingEntryProps {
  activeSearchSeed: SearchSeed | null;
  isLoading: boolean;
  isConfirmationPage?: boolean;
}

const travelerFormFields = [{ type: 'gender' }, { type: 'firstName' }, { type: 'lastName' }, { type: 'birthDate' }];

const mainBookerFormFields = [
  { type: 'street' },
  { type: 'houseNumber' },
  { type: 'box' },
  { type: 'zipCode' },
  { type: 'place' },
  { type: 'country' },
  { type: 'phone' },
  { type: 'email' }
];

const travellersSettings: SharedTravelersSettings = {
  countries: [
    { iso2: 'BE', name: 'Belgium', phonePrefix: '+32' },
    { iso2: 'NL', name: 'Netherlands', phonePrefix: '+31' },
    { iso2: 'FR', name: 'France', phonePrefix: '+33' }
  ],
  formFields: travelerFormFields,
  mainBookerFormFields
};

const BookPackagingEntry: React.FC<BookPackagingEntryProps> = ({ activeSearchSeed, isLoading, isConfirmationPage }) => {
  const context = useContext(SearchResultsConfigurationContext);
  const dispatch = useDispatch();

  const { editablePackagingEntry, priceDetails, currentStep, bookingNumber, selectedPackagingAccoResultCode, packagingAccoResults } = useSelector(
    (state: SearchResultsRootState) => state.searchResults
  );

  const [countries, setCountries] = useState<CountryItem[]>([]);
  const [userValidated, setUserValidated] = useState(true);
  const [remarks, setRemarks] = useState('');
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [selectedPackagingAccoResult, setSelectedPackagingAccoResult] = useState<PackagingAccommodationResponse | null>(null);

  const translations = useMemo(() => getTranslations(context?.languageCode ?? 'en-GB'), [context?.languageCode]);

  const stepLabels = [translations.STEPS.PERSONAL_DETAILS, translations.STEPS.SUMMARY, translations.STEPS.CONFIRMATION];

  const config: TideClientConfig | null = useMemo(() => {
    if (!context) return null;

    return {
      host: context.tideConnection.host,
      apiKey: context.tideConnection.apiKey
    };
  }, [context]);

  const initialValues = useMemo(() => {
    if (!editablePackagingEntry) {
      return {} as TravelersFormValues;
    }

    return createInitialValuesFromEditablePackagingEntry(editablePackagingEntry);
  }, [editablePackagingEntry?.transactionId]);

  const formik = useFormik<TravelersFormValues>({
    initialValues,
    enableReinitialize: true,
    validate: (values) => validateForm(values, false, 'b2c', translations, travellersSettings.formFields, travellersSettings.mainBookerFormFields),
    onSubmit: (values) => {
      if (!editablePackagingEntry) return;

      dispatch(setEditablePackagingEntry(applyTravelersFormValuesToEditablePackagingEntry(editablePackagingEntry, values)));

      dispatch(setCurrentStep(1));
    }
  });

  useEffect(() => {
    if (!context || !config) return;

    const controller = new AbortController();

    (async () => {
      try {
        const result = await getCountries(config, controller.signal);
        setCountries(result.items);
      } catch {
        // optionally handle error
      }
    })();

    return () => controller.abort();
  }, [context, config]);

  useEffect(() => {
    if (isConfirmationPage) {
      dispatch(setCurrentStep(2));
    }
  }, [isConfirmationPage, dispatch]);

  useEffect(() => {
    const selectedPackagingAccoResult = packagingAccoResults?.find((result) => result.code === selectedPackagingAccoResultCode);
    if (selectedPackagingAccoResult) {
      setSelectedPackagingAccoResult(selectedPackagingAccoResult);
    }
  }, [selectedPackagingAccoResultCode, packagingAccoResults]);

  if (!context || !editablePackagingEntry || !priceDetails || !config) return <Spinner label={translations.SUMMARY.PROCESS_BOOKING} />;

  const handleSummarySubmit: React.FormEventHandler<HTMLFormElement> = async (e) => {
    e.preventDefault();

    setIsSubmitting(true);

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

    let updatedEditablePackagingEntry: PackagingEntry = {
      ...editablePackagingEntry,
      remarks
    };

    if (context.generatePaymentUrl && typeof window !== 'undefined') {
      const redirectUrl = new URL(window.location.href);

      redirectUrl.searchParams.set('bookingConfirmation', 'true');
      redirectUrl.searchParams.set('link', '');

      updatedEditablePackagingEntry = {
        ...updatedEditablePackagingEntry,
        redirectUrl: redirectUrl.toString(),
        returnPaymentUrl: true
      };
    }

    dispatch(setEditablePackagingEntry(updatedEditablePackagingEntry));

    try {
      const request = {
        language: context.languageCode ?? 'en-GB',
        officeId: context.tideConnection.officeId,
        catalogueId: context.searchConfiguration.defaultCatalogueId ?? 0,
        agentId: context.agentId,
        payload: updatedEditablePackagingEntry
      } as PackagingRequestBase<PackagingEntry>;

      const bookingResponse = await bookPackagingEntry(config, request);

      dispatch(setBookingNumber(bookingResponse.number));

      if (bookingResponse.paymentUrl) {
        window.location.href = bookingResponse.paymentUrl;
      } else {
        dispatch(setCurrentStep(2));
        setIsSubmitting(false);
      }
    } catch (error) {
      dispatch(setCurrentStep(3));
    }
  };

  return (
    <div className="booking">
      <div className="booking__content">
        <div className="booking__panel">
          <BookingPanel
            currentStep={currentStep}
            stepLabels={stepLabels}
            StepIndicatorsComponent={StepIndicators}
            renderTitle={(step) => (
              <>
                {step + 1}.&nbsp;{stepLabels[step]}
              </>
            )}>
            {isConfirmationPage && isLoading && <Spinner label={translations.SUMMARY.PROCESS_BOOKING} />}
            {currentStep === 0 && (
              <SharedTravelersForm
                formik={formik}
                translations={translations}
                travellersSettings={travellersSettings}
                countries={countries}
                travelersFirstStep={false}
                isUnavailable={false}
                useCompactForm={false}
                showAgentSelection={false}
              />
            )}

            {currentStep === 1 && (
              <SharedSummary
                translations={translations}
                travelerFormValues={formik.values}
                isSubmitting={isSubmitting}
                skipPayment={!context.generatePaymentUrl}
                userValidated={userValidated}
                remarks={remarks}
                enableVoucher={false}
                allowOption={false}
                isOffer={false}
                onUserValidatedChange={setUserValidated}
                onRemarksChange={setRemarks}
                onSubmit={handleSummarySubmit}
                renderOptions={() => renderEditablePackagingEntrySummaryOptions(editablePackagingEntry, priceDetails, translations)}
                renderPreviousButton={() => (
                  <button type="button" title={translations.STEPS.PREVIOUS} onClick={() => dispatch(setCurrentStep(0))} className="cta cta--secondary">
                    {translations.STEPS.PREVIOUS}
                  </button>
                )}
              />
            )}

            {currentStep === 2 && (
              <SharedConfirmation
                bookingNumber={bookingNumber ?? editablePackagingEntry?.dossierNumber ?? ''}
                isOption={false}
                isOffer={false}
                translations={translations.CONFIRMATION}
              />
            )}

            {currentStep === 3 && <div>{/* error */}</div>}
          </BookingPanel>
        </div>

        <div className="backdrop" id="backdrop"></div>

        <WLSidebar activeSearchSeed={activeSearchSeed} packagingAccoResult={selectedPackagingAccoResult} />
      </div>
    </div>
  );
};

export default BookPackagingEntry;
