import React, { useContext, useMemo } from 'react';
import { formatDate, getDateOnlyTime, getTranslations } from '../../../shared/utils/localization-util';
import { SearchResultsRootState } from '../../store/search-results-store';
import { useSelector } from 'react-redux';
import SearchResultsConfigurationContext from '../../search-results-configuration-context';

import { ACCOMMODATION_SERVICE_TYPE, FLIGHT_SERVICE_TYPE } from '../../utils/query-utils';
import { first, last, sum } from 'lodash';
import { SearchSeed } from '../../types';
import { getTravelersText } from '../../../booking-wizard/features/sidebar/sidebar-util';
import { RoomTraveler } from '../../../booking-wizard/types';

import { BookingPackageFlightMetaData, BookingPriceDetail, PackagingAccommodationResponse, PackagingEntryLine, PortalQsmType } from '@qite/tide-client';
import Spinner from '../spinner/spinner';
import SharedSidebar from '../../../shared/booking/shared-sidebar';
import { getImageSrcFromHtml } from '../../../shared/utils/booking-summary';

interface WLSidebarProps {
  activeSearchSeed: SearchSeed | null;
  packagingAccoResult: PackagingAccommodationResponse | null;
}

const mapToSidebarFlightMetaData = (entryLine: PackagingEntryLine) => {
  return {
    flightLines: entryLine.flightInformation?.flightLines.map((f) => ({
      number: f.flightNumber,
      departureDate: f.departureDate,
      departureAirport: f.departureAirportCode,
      departureAirportDescription: f.departureAirportDescription,
      departureTime: f.departureTime,
      arrivalDate: f.arrivalDate,
      arrivalAirport: f.arrivalAirportCode,
      arrivalAirportDescription: f.arrivalAirportDescription,
      arrivalTime: f.arrivalTime,
      flightClass: '',
      travelClass: '',
      airline: f.airlineDescription,
      airlineCode: f.airlineCode,
      operatingAirlineCode: f.operatingAirlineCode,
      operatingAirlineDescription: f.operatingAirlineDescription,
      durationInTicks: f.durationInTicks
    })),
    luggageIncluded: false, // Not present in editablePackagingEntry, set default
    bagageAllowed: false, // Not present in editablePackagingEntry, set default
    bagage: '', // Not present in editablePackagingEntry, set default
    mealIncluded: false, // Not present in editablePackagingEntry, set default
    meal: '', // Not present in editablePackagingEntry, set default
    durationInTicks: entryLine.flightInformation?.flightLines.reduce((s, { durationInTicks }) => s + (durationInTicks ?? 0), 0)
  } as BookingPackageFlightMetaData;
};

const selectSeparatePackagePriceDetails = (priceDetails: BookingPriceDetail[]) => {
  const result: BookingPriceDetail[] = [];
  const filteredPriceDetails = priceDetails.filter((priceDetail) => priceDetail.isSeparate);

  filteredPriceDetails.forEach((priceDetail) => {
    const priceDetailToMerge = result.find(
      (x) => x.productCode === priceDetail.productCode && x.accommodationCode === priceDetail.accommodationCode && x.productType === priceDetail.productType
    );
    if (priceDetailToMerge) {
      priceDetailToMerge.total += priceDetail.total;
      priceDetailToMerge.price += priceDetail.price;
    } else {
      result.push(Object.assign({}, priceDetail));
    }
  });

  return result;
};

const WLSidebar: React.FC<WLSidebarProps> = ({ activeSearchSeed, packagingAccoResult }) => {
  const context = useContext(SearchResultsConfigurationContext);

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

  const translations = getTranslations(context?.languageCode ?? 'en-GB');

  const sortedLines = useMemo(() => {
    return [...(editablePackagingEntry?.lines ?? [])].sort((a, b) => {
      const dateA = getDateOnlyTime(a.from);
      const dateB = getDateOnlyTime(b.from);

      if (dateA !== dateB) {
        return dateA - dateB;
      }

      return (a.order ?? Infinity) - (b.order ?? Infinity);
    });
  }, [editablePackagingEntry]);

  const accoImage = useMemo(() => {
    return getImageSrcFromHtml(packagingAccoResult?.contents);
  }, [packagingAccoResult?.contents]);

  if (!context || !editablePackagingEntry) {
    return null;
  }

  const firstEntryLine = first(sortedLines);
  const accommodationLines = editablePackagingEntry.lines.filter((line) => line.serviceType === ACCOMMODATION_SERVICE_TYPE);
  const accommodationLine = first(accommodationLines) ?? firstEntryLine;

  const location =
    context.searchConfiguration.qsmType === PortalQsmType.Accommodation
      ? packagingAccoResult?.name ??
        accommodationLine?.location?.name ??
        accommodationLine?.oord?.name ??
        accommodationLine?.region?.name ??
        accommodationLine?.country?.name ??
        firstEntryLine?.location?.name
      : accommodationLine?.location?.name ??
        accommodationLine?.oord?.name ??
        accommodationLine?.region?.name ??
        accommodationLine?.country?.name ??
        firstEntryLine?.location?.name;

  const rooms =
    activeSearchSeed?.rooms.map((room) => {
      const adults = room.pax
        .filter((p) => p.age && p.age >= 18)
        .map((p) => {
          return { id: p.id, age: p.age } as RoomTraveler;
        });
      const children = room.pax
        .filter((p) => p.age && p.age < 18)
        .map((p) => {
          return { id: p.id, age: p.age } as RoomTraveler;
        });
      return { adults, children };
    }) || [];

  const travelerRooms = getTravelersText(rooms, translations);

  const flightSegments = sortedLines.filter(
    (line) => line.serviceType === FLIGHT_SERVICE_TYPE && line.flightInformation && Array.isArray(line.flightInformation.flightLines)
  );
  const outboundFlight = first(flightSegments);
  const returnFlight = flightSegments.length > 1 ? last(flightSegments) : undefined;
  const outboundFlightMetaData = outboundFlight ? mapToSidebarFlightMetaData(outboundFlight) : undefined;
  const returnFlightMetaData = returnFlight ? mapToSidebarFlightMetaData(returnFlight) : undefined;

  const basePrice = sum(priceDetails?.details.filter((pd) => pd.isInPackage).map((pd) => pd.price * pd.amount) ?? []);
  const separateExtraPriceDetails = priceDetails?.details.filter((pd) => !pd.isInPackage && pd.isSeparate) ?? [];
  const totalPrice = sum([basePrice, ...separateExtraPriceDetails.map((priceDetail) => priceDetail.price * priceDetail.amount)]);

  const includedCosts = selectSeparatePackagePriceDetails(priceDetails?.details.filter((pd) => pd.isInPackage) ?? []);
  return (
    <SharedSidebar
      productName={location ?? ''}
      thumbnailUrl={accoImage ?? context.destinationImage?.url}
      translations={translations}
      travelerRooms={travelerRooms}
      startDateText={first(sortedLines)?.from && formatDate(new Date(first(sortedLines)!.from))}
      endDateText={last(sortedLines)?.to && formatDate(new Date(last(sortedLines)!.to))}
      isLoading={!editablePackagingEntry || !priceDetails}
      loaderComponent={<Spinner />}
      departureFlightMetaData={outboundFlightMetaData}
      returnFlightMetaData={returnFlightMetaData}
      includedServiceTypes={editablePackagingEntry.lines.map((line) => line.serviceType)}
      packagingAccommodations={accommodationLines}
      basePrice={basePrice}
      commission={priceDetails?.commission}
      totalPrice={totalPrice}
      includedCosts={includedCosts}
      extraCosts={separateExtraPriceDetails}
      deposit={priceDetails?.deposit}
      isUnavailable={false}
      agent={context.agentId}
    />
  );
};

export default WLSidebar;
