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

import {
  getBreakfastPackages,
  getHotelData,
  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 HistoryStateManager from "@/components/HotelReservation/EnterDetails/HistoryStateManager"
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,
  getQueryParamsForEnterDetails,
} from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
import { getIntl } from "@/i18n"
import { setLang } from "@/i18n/serverContext"
import EnterDetailsProvider from "@/providers/EnterDetailsProvider"

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

import type { SelectRateSearchParams } from "@/types/components/hotelReservation/selectRate/selectRate"
import { StepEnum } from "@/types/enums/step"
import type { LangParams, PageArgs } from "@/types/params"

function isValidStep(step: string): step is StepEnum {
  return Object.values(StepEnum).includes(step as StepEnum)
}

export default async function StepPage({
  params: { lang },
  searchParams,
}: PageArgs<LangParams, SelectRateSearchParams & { step: StepEnum }>) {
  if (!isValidStep(searchParams.step)) {
    return notFound()
  }
  setLang(lang)

  const intl = await getIntl()
  const selectRoomParams = new URLSearchParams(searchParams)
  // Deleting step to avoid double searchparams after rewrite
  selectRoomParams.delete("step")
  const booking = getQueryParamsForEnterDetails(selectRoomParams)

  const {
    hotel: hotelId,
    rooms: [
      { adults, children, roomTypeCode, rateCode, packages: packageCodes },
    ], // TODO: Handle multiple rooms
    fromDate,
    toDate,
  } = booking

  const childrenAsString = children && generateChildrenString(children)
  const breakfastInput = { adults, fromDate, hotelId, toDate }
  const selectedRoomAvailabilityInput = {
    adults,
    children: childrenAsString,
    hotelId,
    packageCodes,
    rateCode,
    roomStayStartDate: fromDate,
    roomStayEndDate: toDate,
    roomTypeCode,
  }

  void getProfileSafely()
  void getBreakfastPackages(breakfastInput)
  void getSelectedRoomAvailability(selectedRoomAvailabilityInput)
  if (packageCodes?.length) {
    void getPackages({
      adults,
      children: children?.length,
      endDate: toDate,
      hotelId,
      packageCodes,
      startDate: fromDate,
    })
  }

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

  const roomAvailability = await getSelectedRoomAvailability(
    selectedRoomAvailabilityInput
  )
  const hotelData = await getHotelData({
    hotelId,
    isCardOnlyPayment: roomAvailability?.mustBeGuaranteed,
    language: lang,
  })
  const breakfastPackages = await getBreakfastPackages(breakfastInput)
  const user = await getProfileSafely()

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

  const mustBeGuaranteed = roomAvailability?.mustBeGuaranteed ?? false

  const paymentGuarantee = intl.formatMessage({
    id: "Payment Guarantee",
  })
  const payment = intl.formatMessage({
    id: "Payment",
  })
  const guaranteeWithCard = intl.formatMessage({
    id: "Guarantee booking with credit card",
  })
  const selectPaymentMethod = intl.formatMessage({
    id: "Select payment method",
  })

  const roomPrice = {
    memberPrice: roomAvailability.memberRate?.localPrice.pricePerStay,
    publicPrice: roomAvailability.publicRate!.localPrice.pricePerStay,
  }

  const memberPrice = roomAvailability.memberRate
    ? {
        price: roomAvailability.memberRate.localPrice.pricePerStay,
        currency: roomAvailability.memberRate.localPrice.currency,
      }
    : undefined

  const summary = {
    cancellationText: roomAvailability.cancellationText,
    isMember: !!user,
    rateDetails: roomAvailability.rateDetails,
    roomType: roomAvailability.selectedRoom.roomType,
  }

  return (
    <EnterDetailsProvider
      bedTypes={roomAvailability.bedTypes}
      booking={booking}
      breakfastPackages={breakfastPackages}
      packages={packages}
      roomRate={{
        memberRate: roomAvailability.memberRate,
        publicRate: roomAvailability.publicRate,
      }}
      searchParamsStr={selectRoomParams.toString()}
      step={searchParams.step}
      user={user}
    >
      <main>
        <HotelHeader hotelData={hotelData} />
        <div className={styles.container}>
          <div className={styles.content}>
            <section>
              <HistoryStateManager />
              <SelectedRoom
                hotelId={hotelId}
                room={roomAvailability.selectedRoom}
                rateDescription={roomAvailability.cancellationText}
              />

              {/* TODO: How to handle no beds found? */}
              {roomAvailability.bedTypes ? (
                <SectionAccordion
                  header={intl.formatMessage({ id: "Select bed" })}
                  label={intl.formatMessage({ id: "Request bedtype" })}
                  step={StepEnum.selectBed}
                >
                  <BedType bedTypes={roomAvailability.bedTypes} />
                </SectionAccordion>
              ) : null}

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

              <SectionAccordion
                header={intl.formatMessage({ id: "Details" })}
                step={StepEnum.details}
                label={intl.formatMessage({ id: "Enter your details" })}
              >
                <Details user={user} memberPrice={memberPrice} />
              </SectionAccordion>

              <SectionAccordion
                header={mustBeGuaranteed ? paymentGuarantee : payment}
                step={StepEnum.payment}
                label={
                  mustBeGuaranteed ? guaranteeWithCard : selectPaymentMethod
                }
              >
                <Suspense>
                  <Payment
                    user={user}
                    roomPrice={roomPrice}
                    otherPaymentOptions={
                      hotelData.data.attributes.merchantInformationData
                        .alternatePaymentOptions
                    }
                    supportedCards={
                      hotelData.data.attributes.merchantInformationData.cards
                    }
                    mustBeGuaranteed={mustBeGuaranteed}
                  />
                </Suspense>
              </SectionAccordion>
            </section>
          </div>
          <aside className={styles.summary}>
            <MobileSummary {...summary} />
            <DesktopSummary {...summary} />
          </aside>
        </div>
      </main>
    </EnterDetailsProvider>
  )
}
