import { BookingStatusEnum, CancellationRuleEnum } from "@/constants/booking"
import { dt } from "@/lib/dt"

import { convertToChildType } from "../../utils/convertToChildType"
import { getPriceType } from "../../utils/getPriceType"
import { formatChildBedPreferences } from "../utils"

import type { BreakfastPackage } from "@/types/components/hotelReservation/breakfast"
import { RoomPackageCodeEnum } from "@/types/components/hotelReservation/selectRate/roomFilter"
import { BreakfastPackageEnum } from "@/types/enums/breakfast"
import { PackageTypeEnum } from "@/types/enums/packages"
import type { RateEnum } from "@/types/enums/rate"
import type { Room } from "@/types/hotel"
import type { Room as MyStayRoom } from "@/types/stores/my-stay"
import type { BookingConfirmation } from "@/types/trpc/routers/booking/confirmation"

interface MapRoomDetailsParams {
  booking: BookingConfirmation["booking"]
  rates: Record<RateEnum, string>
  room: (Room & { bedType: Room["roomTypes"][number] }) | null
  roomNumber: number
}

export function mapRoomDetails({
  booking,
  rates,
  room,
  roomNumber,
}: MapRoomDetailsParams): MyStayRoom {
  const nights = dt(booking.checkOutDate)
    .startOf("day")
    .diff(dt(booking.checkInDate).startOf("day"), "days")

  const validBreakfastPackagesAdults: string[] = [
    BreakfastPackageEnum.REGULAR_BREAKFAST,
    BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST,
  ]
  const breakfastPackageAdults = booking.packages.find((pkg) =>
    validBreakfastPackagesAdults.includes(pkg.code)
  )

  // We don't get `requestedPrice` in packages
  let breakfast: Omit<BreakfastPackage, "requestedPrice"> | undefined | false
  if (breakfastPackageAdults) {
    breakfast = {
      code: breakfastPackageAdults.code,
      description: breakfastPackageAdults.description,
      localPrice: {
        currency: breakfastPackageAdults.currency,
        price: breakfastPackageAdults.unitPrice,
        totalPrice: breakfastPackageAdults.totalPrice,
      },
      packageType: PackageTypeEnum.BreakfastAdult,
    }
  } else if (!booking.rateDefinition.breakfastIncluded) {
    breakfast = false
  }

  const validBreakfastPackagesChildren: string[] = [
    BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
  ]
  const breakfastPackageChildren = booking.packages.find((pkg) =>
    validBreakfastPackagesChildren.includes(pkg.code)
  )
  // We don't get `requestedPrice` in packages
  const breakfastChildren: Omit<BreakfastPackage, "requestedPrice"> | null =
    breakfastPackageChildren && !booking.rateDefinition.breakfastIncluded
      ? {
          code: breakfastPackageChildren.code,
          description: breakfastPackageChildren.description,
          localPrice: {
            currency: breakfastPackageChildren.currency,
            price: breakfastPackageChildren.unitPrice,
            totalPrice: breakfastPackageChildren.totalPrice,
          },
          packageType: PackageTypeEnum.BreakfastChildren,
        }
      : null

  const isCancelled = booking.reservationStatus === BookingStatusEnum.Cancelled

  const childrenAsString = formatChildBedPreferences({
    childrenAges: booking.childrenAges,
    childBedPreferences: booking.childBedPreferences,
  })

  const childrenInRoom = convertToChildType(
    booking.childrenAges,
    booking.childBedPreferences
  )

  const priceType = getPriceType(
    booking.cheques,
    booking.totalPoints,
    booking.vouchers
  )

  let rate = ""
  if (booking.rateDefinition.cancellationRule) {
    switch (booking.rateDefinition.cancellationRule) {
      case CancellationRuleEnum.CancellableBefore6PM:
        rate = rates.flex
        break
      case CancellationRuleEnum.Changeable:
        rate = rates.change
        break
      case CancellationRuleEnum.NonCancellable:
        rate = rates.save
        break
    }
  }

  const featuresPackages = booking.packages.filter(
    (pkg) =>
      pkg.code === RoomPackageCodeEnum.PET_ROOM ||
      pkg.code === RoomPackageCodeEnum.ALLERGY_ROOM ||
      pkg.code === RoomPackageCodeEnum.ACCESSIBILITY_ROOM
  )

  const packages = featuresPackages.map((pkg) => ({
    code: pkg.code as RoomPackageCodeEnum,
    description: pkg.description,
    inventories: [],
    itemCode: "",
    localPrice: {
      currency: pkg.currency,
      price: pkg.unitPrice,
      totalPrice: pkg.totalPrice,
    },
    requestedPrice: {
      currency: pkg.currency,
      price: pkg.unitPrice,
      totalPrice: pkg.totalPrice,
    },
  }))

  return {
    ...booking,
    bedType: {
      description: room?.bedType.mainBed.description ?? "",
      roomTypeCode: room?.bedType.code ?? "",
    },
    breakfast,
    breakfastChildren,
    childrenAsString,
    childrenInRoom,
    isCancelled,
    originalPackages: booking.packages,
    packages,
    priceType,
    rate,
    room,
    roomName: room?.name ?? "",
    roomNumber,
    roomPrice: {
      perNight: {
        local: {
          currency: booking.currencyCode,
          price: isCancelled ? 0 : booking.roomPrice / nights,
        },
        requested: undefined,
      },
      perStay: {
        local: {
          currency: booking.currencyCode,
          price: isCancelled ? 0 : booking.roomPrice,
        },
        requested: undefined,
      },
    },
    terms: booking.rateDefinition.cancellationText,
  }
}
