import { cookies } from "next/headers"
import { notFound } from "next/navigation"

import { Typography } from "@scandic-hotels/design-system/Typography"

import { env } from "@/env/server"
import { dt } from "@/lib/dt"
import {
  findBooking,
  getAncillaryPackages,
  getBookingConfirmation,
  getLinkedReservations,
  getPackages,
  getProfileSafely,
  getSavedPaymentCardsSafely,
} from "@/lib/trpc/memoizedRequests"

import { auth } from "@/auth"
import AdditionalInfoForm from "@/components/HotelReservation/FindMyBooking/AdditionalInfoForm"
import accessBooking, {
  ACCESS_GRANTED,
  ERROR_BAD_REQUEST,
  ERROR_UNAUTHORIZED,
} from "@/components/HotelReservation/MyStay/accessBooking"
import { Ancillaries } from "@/components/HotelReservation/MyStay/Ancillaries"
import BookingSummary from "@/components/HotelReservation/MyStay/BookingSummary"
import { Header } from "@/components/HotelReservation/MyStay/Header"
import Promo from "@/components/HotelReservation/MyStay/Promo"
import { ReferenceCard } from "@/components/HotelReservation/MyStay/ReferenceCard"
import MultiRoom from "@/components/HotelReservation/MyStay/Rooms/MultiRoom"
import SingleRoom from "@/components/HotelReservation/MyStay/Rooms/SingleRoom"
import SidePeek from "@/components/HotelReservation/SidePeek"
import Image from "@/components/Image"
import { getIntl } from "@/i18n"
import { setLang } from "@/i18n/serverContext"
import MyStayProvider from "@/providers/MyStay"
import { parseRefId } from "@/utils/refId"
import { isValidSession } from "@/utils/session"
import { getCurrentWebUrl } from "@/utils/url"

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

import { BreakfastPackageEnum } from "@/types/enums/breakfast"
import type { LangParams, PageArgs } from "@/types/params"

export default async function MyStay({
  params,
  searchParams,
}: PageArgs<LangParams, { RefId?: string }>) {
  setLang(params.lang)
  const refId = searchParams.RefId

  if (!refId) {
    notFound()
  }

  const { confirmationNumber, lastName } = parseRefId(refId)

  if (!confirmationNumber) {
    return notFound()
  }

  const session = await auth()
  const isLoggedIn = isValidSession(session)

  const bv = cookies().get("bv")?.value
  let bookingConfirmation
  if (isLoggedIn) {
    bookingConfirmation = await getBookingConfirmation(refId)
  } else if (bv) {
    const params = new URLSearchParams(bv)
    const firstName = params.get("firstName")
    const email = params.get("email")

    if (firstName && email) {
      bookingConfirmation = await findBooking(
        confirmationNumber,
        lastName,
        firstName,
        email
      )
    } else {
      return (
        <RenderAdditionalInfoForm
          confirmationNumber={confirmationNumber}
          lastName={lastName}
        />
      )
    }
  } else {
    return (
      <RenderAdditionalInfoForm
        confirmationNumber={confirmationNumber}
        lastName={lastName}
      />
    )
  }
  if (!bookingConfirmation) {
    return notFound()
  }

  const { additionalData, booking, hotel, roomCategories } = bookingConfirmation

  const user = await getProfileSafely()
  const intl = await getIntl()

  const access = accessBooking(booking.guest, lastName, user, bv)

  if (access === ACCESS_GRANTED) {
    const lang = params.lang
    const fromDate = dt(booking.checkInDate).format("YYYY-MM-DD")
    const toDate = dt(booking.checkOutDate).format("YYYY-MM-DD")

    const linkedReservationsPromise = getLinkedReservations(booking.refId)

    const ancillariesInput = {
      fromDate,
      hotelId: hotel.operaId,
      toDate,
    }
    const packagesInput = {
      adults: booking.adults,
      children: booking.childrenAges.length,
      endDate: toDate,
      hotelId: hotel.operaId,
      lang,
      startDate: fromDate,
      packageCodes: [
        BreakfastPackageEnum.ANCILLARY_REGULAR_BREAKFAST,
        BreakfastPackageEnum.ANCILLARY_CHILD_PAYING_BREAKFAST,
        BreakfastPackageEnum.FREE_CHILD_BREAKFAST,
      ],
    }
    const supportedCards = hotel.merchantInformationData.cards
    const savedPaymentCardsInput = { supportedCards }

    const hasBreakfastPackage = booking.packages.find(
      (pkg) => pkg.code === BreakfastPackageEnum.REGULAR_BREAKFAST
    )
    const breakfastIncluded = booking.rateDefinition.breakfastIncluded
    const shouldFetchBreakfastPackages =
      !hasBreakfastPackage && !breakfastIncluded
    if (shouldFetchBreakfastPackages) {
      void getPackages(packagesInput)
    }
    if (user) {
      void getSavedPaymentCardsSafely(savedPaymentCardsInput)
    }
    if (booking.showAncillaries) {
      void getAncillaryPackages(ancillariesInput)
    }

    let breakfastPackages = null
    if (shouldFetchBreakfastPackages) {
      breakfastPackages = await getPackages(packagesInput)
    }
    let savedCreditCards = null
    if (user) {
      savedCreditCards = await getSavedPaymentCardsSafely(
        savedPaymentCardsInput
      )
    }
    let ancillaryPackagesPromise = null
    if (booking.showAncillaries) {
      ancillaryPackagesPromise = getAncillaryPackages(ancillariesInput)
    }

    const imageSrc =
      hotel.hotelContent.images.imageSizes.large ??
      additionalData.gallery?.heroImages[0]?.imageSizes.large ??
      hotel.galleryImages[0]?.imageSizes.large

    const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
    const promoUrl = !env.isLangLive(params.lang)
      ? new URL(getCurrentWebUrl({ path: "/", lang }))
      : new URL(`${baseUrl}/${lang}/`)

    promoUrl.searchParams.set("hotel", hotel.operaId)

    return (
      <MyStayProvider
        bookingConfirmation={bookingConfirmation}
        breakfastPackages={breakfastPackages}
        lang={params.lang}
        linkedReservationsPromise={linkedReservationsPromise}
        refId={booking.refId}
        roomCategories={roomCategories}
        savedCreditCards={savedCreditCards}
      >
        <main className={styles.main}>
          <div className={styles.imageContainer}>
            <div className={styles.blurOverlay} />
            {imageSrc && (
              <Image
                className={styles.image}
                src={imageSrc}
                alt={hotel.name}
                fill
              />
            )}
          </div>
          <div className={styles.content}>
            <div className={styles.headerContainer}>
              <Header cityName={hotel.cityName} name={hotel.name} />
              <ReferenceCard />
            </div>
            {booking.showAncillaries && ancillaryPackagesPromise && (
              <Ancillaries
                ancillariesPromise={ancillaryPackagesPromise}
                packages={breakfastPackages}
                user={user}
                savedCreditCards={savedCreditCards}
              />
            )}

            <SingleRoom user={user} />
            <MultiRoom user={user} />

            <BookingSummary hotel={hotel} />
            <Promo
              title={intl.formatMessage({
                defaultMessage: "Book your next stay",
              })}
              text={intl.formatMessage({
                defaultMessage:
                  "Get inspired and start dreaming beyond your next trip. Explore more Scandic destinations.",
              })}
              buttonText={intl.formatMessage({
                defaultMessage: "Explore Scandic hotels",
              })}
              href={promoUrl.toString()}
              image={hotel.hotelContent.images}
            />
          </div>
        </main>
        <SidePeek />
      </MyStayProvider>
    )
  }

  if (access === ERROR_BAD_REQUEST) {
    return (
      <main className={styles.main}>
        <div className={styles.form}>
          <AdditionalInfoForm
            confirmationNumber={confirmationNumber}
            lastName={lastName}
          />
        </div>
      </main>
    )
  }

  if (access === ERROR_UNAUTHORIZED) {
    return (
      <main className={styles.main}>
        <div className={styles.logIn}>
          <Typography variant="Title/md">
            <h1>
              {intl.formatMessage({
                defaultMessage: "You need to be logged in to view your booking",
              })}
            </h1>
          </Typography>
          <Typography variant="Body/Lead text">
            <p>
              {intl.formatMessage({
                defaultMessage:
                  "And you need to be logged in with the same member account that made the booking.",
              })}
            </p>
          </Typography>
        </div>
      </main>
    )
  }

  return notFound()
}

function RenderAdditionalInfoForm({
  confirmationNumber,
  lastName,
}: {
  confirmationNumber: string
  lastName: string
}) {
  return (
    <main className={styles.main}>
      <div className={styles.form}>
        <AdditionalInfoForm
          confirmationNumber={confirmationNumber}
          lastName={lastName}
        />
      </div>
    </main>
  )
}
