import {
  BookingPackageAvailability,
  BookingPackageRoom,
} from "@qite/tide-client/build/types";
import {
  AccommodationContent,
  RegimeContent,
  SelectableRoom,
  SelectableRoomAccommodation,
} from "../../types";

export const buildSelectableRooms = (
  packageRooms: BookingPackageRoom[],
  accommodations: AccommodationContent[] | undefined,
  regimes: RegimeContent[] | undefined,
  accommodationViews: { [key: string]: string } | undefined
) => {
  return packageRooms.map((x) => {
    const selectedOption = x.options.find((x) => x.isSelected)!;
    const alternativeOptions = x.options
      .filter(
        (x) =>
          x.accommodationCode !== selectedOption.accommodationCode &&
          !x.isLocked
      )
      .sort((a, b) => a.price - b.price);

    const alternativeAccommodations: SelectableRoomAccommodation[] = [];
    alternativeOptions.forEach((x) => {
      const alternativeAccommodation = alternativeAccommodations.find(
        (y) => y.code === x.accommodationCode
      );

      if (alternativeAccommodation) {
        const regime = regimes?.find((y) => y.code === x.regimeCode);

        alternativeAccommodation.regimes.push({
          code: x.regimeCode,
          title: regime?.title ?? x.regimeName,
          price: x.price,
        });
      } else {
        const accommodation = accommodations?.find(
          (y) => y.code === x.accommodationCode
        );
        const regime = regimes?.find((y) => y.code === x.regimeCode);

        alternativeAccommodations.push({
          code: x.accommodationCode,
          regimeCode: x.regimeCode,
          from: x.from,
          to: x.to,
          price: x.price,
          regimes: [
            {
              code: x.regimeCode,
              title: regime?.title ?? x.regimeName,
              price: x.price,
            },
          ],
          title: accommodation?.title ?? x.accommodationName,
          image: accommodation?.imageUrl,
          usps: accommodation?.usps ?? [],
          description: accommodation?.description,
          viewHtml: accommodationViews?.[x.accommodationCode],
        });
      }
    });

    const accommodation = accommodations?.find(
      (y) => y.code === selectedOption.accommodationCode
    );

    return {
      index: x.index,
      selected: {
        code: selectedOption.accommodationCode,
        regimeCode: selectedOption.regimeCode,
        price: selectedOption.price,
        from: selectedOption.from,
        to: selectedOption.to,
        regimes: x.options
          .filter(
            (x) => x.accommodationCode === selectedOption.accommodationCode
          )
          .sort((a, b) => a.price - b.price)
          .map((o) => {
            const regime = regimes?.find((y) => y.code === o.regimeCode);

            return {
              code: o.regimeCode,
              title: regime?.title ?? o.regimeName,
              price: o.price,
            };
          }),
        title: accommodation?.title ?? selectedOption.accommodationName,
        image: accommodation?.imageUrl,
        usps: accommodation?.usps ?? [],
        description: accommodation?.description,
        viewHtml: accommodationViews?.[selectedOption.accommodationCode],
      },
      showAlternatives: false,
      alternatives: alternativeAccommodations,
    } as SelectableRoom;
  });
};

export const updatePackageRooms = (
  rooms: BookingPackageRoom[],
  index: number,
  accommodationCode: string,
  regimeCode: string | null,
  availabilities: BookingPackageAvailability[]
) => {
  const updatedRooms = rooms.map((room) => {
    if (room.index !== index) return room;

    return {
      ...room,
      options: room.options.map((option) => {
        return {
          ...option,
          isSelected:
            option.accommodationCode === accommodationCode &&
            (option.regimeCode === regimeCode ||
              (option.regimeCode === null && regimeCode === "")),
        };
      }),
    };
  });

  const selectedAccommodations = new Map<string, number>();
  updatedRooms
    .map((x) => x.options.find((x) => x.isSelected)!)
    .forEach((x) => {
      if (selectedAccommodations.has(x.accommodationCode)) {
        selectedAccommodations.set(
          x.accommodationCode,
          selectedAccommodations.get(x.accommodationCode)! + 1
        );
      } else {
        selectedAccommodations.set(x.accommodationCode, 1);
      }
    });

  const accoCounter = availabilities.map((x) => ({
    code: x.code,
    count: x.count,
  }));
  return updatedRooms.map((room) => {
    const selectedOption = room.options.find((x) => x.isSelected)!;

    return {
      ...room,
      options: room.options.map((option) => {
        const isCurrentOption =
          selectedOption.accommodationCode === option.accommodationCode;
        const usedCount =
          selectedAccommodations.get(option.accommodationCode) ?? 0;
        const availability = availabilities.find(
          (x) => x.code === option.accommodationCode
        );

        if (availability) {
          const accoCount = accoCounter.find(
            (x) => x.code === option.accommodationCode
          )!;

          const roomsLeft = availability.count - usedCount;
          let isOnRequest = isCurrentOption
            ? accoCount.count < 0 && (availability?.onRequestPossible ?? false)
            : roomsLeft < 0 && (availability?.onRequestPossible ?? false);
          if (isCurrentOption) accoCount.count--;

          return {
            ...option,
            isLocked:
              !option.isSelected &&
              !isOnRequest &&
              roomsLeft < 0 &&
              !availability.isExternal,
            isOnRequest: isOnRequest,
          };
        } else {
          return option;
        }
      }),
    };
  });
};
