import { notFound } from "next/navigation"
import { Suspense } from "react"

import {
  getBreakfastPackages,
  getHotel,
  getPackages,
  getProfileSafely,
  getSelectedRoomAvailability,
} from "@/lib/trpc/memoizedRequests"

import BedType from "@/components/HotelReservation/EnterDetails/BedType"
import Breakfast from "@/components/HotelReservation/EnterDetails/Breakfast"
import Details from "@/components/HotelReservation/EnterDetails/Details"
import HotelHeader from "@/components/HotelReservation/EnterDetails/Header"
import Payment from "@/components/HotelReservation/EnterDetails/Payment"
import SectionAccordion from "@/components/HotelReservation/EnterDetails/SectionAccordion"
import SelectedRoom from "@/components/HotelReservation/EnterDetails/SelectedRoom"
import DesktopSummary from "@/components/HotelReservation/EnterDetails/Summary/Desktop"
import MobileSummary from "@/components/HotelReservation/EnterDetails/Summary/Mobile"
import { generateChildrenString } from "@/components/HotelReservation/utils"
import Title from "@/components/TempDesignSystem/Text/Title"
import { getIntl } from "@/i18n"
import EnterDetailsProvider from "@/providers/EnterDetailsProvider"
import { convertSearchParamsToObj } from "@/utils/url"

import styles from "./page.module.css"

import type { BedTypeSelection } from "@/types/components/hotelReservation/enterDetails/bedType"
import type { RoomRate } from "@/types/components/hotelReservation/enterDetails/details"
import { type SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { StepEnum } from "@/types/enums/step"
import type { LangParams, PageArgs } from "@/types/params"
import type { Packages } from "@/types/requests/packages"

export interface RoomData {
  bedTypes?: BedTypeSelection[]
  mustBeGuaranteed?: boolean
  breakfastIncluded?: boolean
  packages: Packages | null
  cancellationText: string
  rateDetails: string[]
  roomType: string
  roomRate: RoomRate
}

export default async function DetailsPage({
  params: { lang },
  searchParams,
}: PageArgs<LangParams, SelectRateSearchParams>) {
  const intl = await getIntl()
  const selectRoomParams = new URLSearchParams(searchParams)
  const booking = convertSearchParamsToObj<SelectRateSearchParams>(searchParams)

  void getProfileSafely()

  const breakfastInput = {
    adults: 1,
    fromDate: booking.fromDate,
    hotelId: booking.hotelId,
    toDate: booking.toDate,
  }
  const breakfastPackages = await getBreakfastPackages(breakfastInput)
  const roomsData: RoomData[] = []

  for (let room of booking.rooms) {
    const childrenAsString =
      room.childrenInRoom && generateChildrenString(room.childrenInRoom)

    const selectedRoomAvailabilityInput = {
      adults: room.adults,
      children: childrenAsString,
      hotelId: booking.hotelId,
      packageCodes: room.packages,
      rateCode: room.rateCode,
      roomStayStartDate: booking.fromDate,
      roomStayEndDate: booking.toDate,
      roomTypeCode: room.roomTypeCode,
    }

    const packages = room.packages
      ? await getPackages({
          adults: room.adults,
          children: room.childrenInRoom?.length,
          endDate: booking.toDate,
          hotelId: booking.hotelId,
          packageCodes: room.packages,
          startDate: booking.fromDate,
          lang,
        })
      : null

    const roomAvailability = await getSelectedRoomAvailability(
      selectedRoomAvailabilityInput //
    )

    if (!roomAvailability) {
      continue // TODO: handle no room availability
    }

    roomsData.push({
      bedTypes: roomAvailability.bedTypes,
      packages,
      mustBeGuaranteed: roomAvailability.mustBeGuaranteed,
      breakfastIncluded: roomAvailability.breakfastIncluded,
      cancellationText: roomAvailability.cancellationText,
      rateDetails: roomAvailability.rateDetails ?? [],
      roomType: roomAvailability.selectedRoom.roomType,
      roomRate: {
        memberRate: roomAvailability?.memberRate,
        publicRate: roomAvailability.publicRate,
      },
    })
  }

  const isCardOnlyPayment = roomsData.some((room) => room?.mustBeGuaranteed)
  const hotelData = await getHotel({
    hotelId: booking.hotelId,
    isCardOnlyPayment,
    language: lang,
  })
  const user = await getProfileSafely()
  // const userTrackingData = await getUserTracking()

  if (!hotelData || !roomsData) {
    return notFound()
  }

  // const arrivalDate = new Date(booking.fromDate)
  // const departureDate = new Date(booking.toDate)
  const hotelAttributes = hotelData.hotel

  // TODO: add tracking
  // const initialHotelsTrackingData: TrackingSDKHotelInfo = {
  //   searchTerm: searchParams.city,
  //   arrivalDate: format(arrivalDate, "yyyy-MM-dd"),
  //   departureDate: format(departureDate, "yyyy-MM-dd"),
  //   noOfAdults: adults,
  //   noOfChildren: childrenInRoom?.length,
  //   ageOfChildren: childrenInRoom?.map((c) => c.age).join(","),
  //   childBedPreference: childrenInRoom
  //     ?.map((c) => ChildBedMapEnum[c.bed])
  //     .join("|"),
  //   noOfRooms: 1, // // TODO: Handle multiple rooms
  //   duration: differenceInCalendarDays(departureDate, arrivalDate),
  //   leadTime: differenceInCalendarDays(arrivalDate, new Date()),
  //   searchType: "hotel",
  //   bookingTypeofDay: isWeekend(arrivalDate) ? "weekend" : "weekday",
  //   country: hotelAttributes?.address.country,
  //   hotelID: hotelAttributes?.operaId,
  //   region: hotelAttributes?.address.city,
  // }

  const showBreakfastStep = Boolean(
    breakfastPackages?.length && !roomsData[0]?.breakfastIncluded
  )

  return (
    <EnterDetailsProvider
      booking={booking}
      showBreakfastStep={showBreakfastStep}
      roomsData={roomsData}
      searchParamsStr={selectRoomParams.toString()}
      user={user}
      vat={hotelAttributes.vat}
    >
      <main>
        <HotelHeader hotelData={hotelData} />
        <div className={styles.container}>
          <div className={styles.content}>
            {roomsData.map((room, idx) => (
              <section key={idx}>
                {roomsData.length > 1 && (
                  <header className={styles.header}>
                    <Title level="h2" as="h4">
                      {intl.formatMessage({ id: "Room" })} {idx + 1}
                    </Title>
                  </header>
                )}
                <SelectedRoom
                  hotelId={booking.hotelId}
                  roomType={room.roomType}
                  roomTypeCode={booking.rooms[idx].roomTypeCode}
                  rateDescription={room.cancellationText}
                  roomIndex={idx}
                  searchParamsStr={selectRoomParams.toString()}
                />

                {room.bedTypes ? (
                  <SectionAccordion
                    header={intl.formatMessage({ id: "Select bed" })}
                    label={intl.formatMessage({ id: "Request bedtype" })}
                    step={StepEnum.selectBed}
                    roomIndex={idx}
                  >
                    <BedType bedTypes={room.bedTypes} roomIndex={idx} />
                  </SectionAccordion>
                ) : null}

                {showBreakfastStep ? (
                  <SectionAccordion
                    header={intl.formatMessage({ id: "Food options" })}
                    label={intl.formatMessage({
                      id: "Select breakfast options",
                    })}
                    step={StepEnum.breakfast}
                    roomIndex={idx}
                  >
                    <Breakfast packages={breakfastPackages!} roomIndex={idx} />
                  </SectionAccordion>
                ) : null}

                <SectionAccordion
                  header={intl.formatMessage({ id: "Details" })}
                  step={StepEnum.details}
                  label={intl.formatMessage({ id: "Enter your details" })}
                  roomIndex={idx}
                >
                  <Details
                    user={idx === 0 ? user : null}
                    memberPrice={{
                      currency:
                        room?.roomRate.memberRate?.localPrice.currency ?? "", // TODO: how to handle undefined,
                      price:
                        room?.roomRate.memberRate?.localPrice.pricePerNight ??
                        0, // TODO: how to handle undefined,
                    }}
                    roomIndex={idx}
                  />
                </SectionAccordion>
              </section>
            ))}
            <Suspense>
              <Payment
                user={user}
                otherPaymentOptions={
                  hotelAttributes.merchantInformationData
                    .alternatePaymentOptions
                }
                supportedCards={hotelAttributes.merchantInformationData.cards}
                mustBeGuaranteed={isCardOnlyPayment}
              />
            </Suspense>
          </div>
          <aside className={styles.summary}>
            <MobileSummary
              isMember={!!user}
              breakfastIncluded={roomsData[0]?.breakfastIncluded ?? false}
            />
            <DesktopSummary
              isMember={!!user}
              breakfastIncluded={roomsData[0]?.breakfastIncluded ?? false}
            />
          </aside>
        </div>
      </main>
    </EnterDetailsProvider>
  )
}
