import { notFound } from "next/navigation"

import {
  getBreakfastPackages,
  getCreditCardsSafely,
  getHotelData,
  getProfileSafely,
  getSelectedRoomAvailability,
} from "@/lib/trpc/memoizedRequests"
import { HotelIncludeEnum } from "@/server/routers/hotels/input"

import BedType from "@/components/HotelReservation/EnterDetails/BedType"
import Breakfast from "@/components/HotelReservation/EnterDetails/Breakfast"
import Details from "@/components/HotelReservation/EnterDetails/Details"
import HistoryStateManager from "@/components/HotelReservation/EnterDetails/HistoryStateManager"
import Payment from "@/components/HotelReservation/EnterDetails/Payment"
import SectionAccordion from "@/components/HotelReservation/EnterDetails/SectionAccordion"
import { getQueryParamsForEnterDetails } from "@/components/HotelReservation/SelectRate/RoomSelection/utils"
import { getIntl } from "@/i18n"

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

export function preload() {
  void getProfileSafely()
  void getCreditCardsSafely()
}

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

export default async function StepPage({
  params,
  searchParams,
}: PageArgs<LangParams & { step: StepEnum }, SelectRateSearchParams>) {
  const { lang } = params

  const intl = await getIntl()
  const selectRoomParams = new URLSearchParams(searchParams)
  const {
    hotel: hotelId,
    adults,
    children,
    roomTypeCode,
    rateCode,
    fromDate,
    toDate,
  } = getQueryParamsForEnterDetails(selectRoomParams)

  const breakfastInput = { adults, fromDate, hotelId, toDate }
  void getBreakfastPackages(breakfastInput)
  void getSelectedRoomAvailability({
    hotelId: parseInt(searchParams.hotel),
    adults,
    children,
    roomStayStartDate: fromDate,
    roomStayEndDate: toDate,
    rateCode,
    roomTypeCode,
  })

  const hotelData = await getHotelData({
    hotelId,
    language: lang,
    include: [HotelIncludeEnum.RoomCategories],
  })
  const roomAvailability = await getSelectedRoomAvailability({
    hotelId: parseInt(searchParams.hotel),
    adults,
    children,
    roomStayStartDate: fromDate,
    roomStayEndDate: toDate,
    rateCode,
    roomTypeCode,
  })
  const breakfastPackages = await getBreakfastPackages(breakfastInput)
  const user = await getProfileSafely()
  const savedCreditCards = await getCreditCardsSafely()

  if (!isValidStep(params.step) || !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 availableRoom = roomAvailability.selectedRoom?.roomType
  const bedTypes = hotelData.included
    ?.find((room) => room.name === availableRoom)
    ?.roomTypes.map((room) => ({
      description: room.mainBed.description,
      size: room.mainBed.widthRange,
      value: room.code,
    }))

  return (
    <section>
      <HistoryStateManager />

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

      <SectionAccordion
        header={intl.formatMessage({ id: "Food options" })}
        step={StepEnum.breakfast}
        label={intl.formatMessage({ id: "Select breakfast options" })}
      >
        <Breakfast packages={breakfastPackages} />
      </SectionAccordion>
      <SectionAccordion
        header={intl.formatMessage({ id: "Details" })}
        step={StepEnum.details}
        label={intl.formatMessage({ id: "Enter your details" })}
      >
        <Details user={user} />
      </SectionAccordion>
      <SectionAccordion
        header={mustBeGuaranteed ? paymentGuarantee : payment}
        step={StepEnum.payment}
        label={mustBeGuaranteed ? guaranteeWithCard : selectPaymentMethod}
      >
        <Payment
          hotelId={searchParams.hotel}
          otherPaymentOptions={
            hotelData.data.attributes.merchantInformationData
              .alternatePaymentOptions
          }
          savedCreditCards={savedCreditCards}
          mustBeGuaranteed={mustBeGuaranteed}
        />
      </SectionAccordion>
    </section>
  )
}
