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

import { filterOverlappingDates } from "@scandic-hotels/booking-flow/utils/SelectRate"
import { dt } from "@scandic-hotels/common/dt"
import { logger } from "@scandic-hotels/common/logger"
import * as maskValue from "@scandic-hotels/common/utils/maskValue"
import Image from "@scandic-hotels/design-system/Image"
import { Typography } from "@scandic-hotels/design-system/Typography"
import { BreakfastPackageEnum } from "@scandic-hotels/trpc/enums/breakfast"
import { parseRefId } from "@scandic-hotels/trpc/utils/refId"

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

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 { getIntl } from "@/i18n"
import MyStayProvider from "@/providers/MyStay"
import { isLoggedInUser } from "@/utils/isLoggedInUser"

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

import type { AdditionalInfoCookieValue } from "@scandic-hotels/booking-flow/types/components/findMyBooking/additionalInfoCookieValue"
import type { Lang } from "@scandic-hotels/common/constants/language"
import type { BookingConfirmation } from "@scandic-hotels/trpc/types/bookingConfirmation"

import type { SafeUser } from "@/types/user"

export default async function MyStay(props: {
  refId?: string
  lang: Lang
  isWebview?: boolean
}) {
  const { refId, lang, isWebview } = props

  if (!refId) {
    notFound()
  }

  const { confirmationNumber, lastName } = parseRefId(refId)
  if (!confirmationNumber) {
    return notFound()
  }

  const isLoggedIn = await isLoggedInUser()

  const cookieStore = await cookies()
  const bv = cookieStore.get("bv")?.value
  let bookingConfirmation
  if (isLoggedIn) {
    bookingConfirmation = await getBookingConfirmation(refId)
  } else if (bv) {
    logger.info(`MyStay: bv`, bv)
    const values = JSON.parse(bv) as AdditionalInfoCookieValue
    const firstName = values.firstName
    const email = values.email
    const bvConfirmationNo = values.confirmationNumber

    if (firstName && email && bvConfirmationNo === confirmationNumber) {
      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 fromDate = dt(booking.checkInDate).format("YYYY-MM-DD")
    const toDate = dt(booking.checkOutDate).format("YYYY-MM-DD")

    const linkedReservationsPromise = getLinkedReservations(booking.refId)

    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)
    }
    const isOwnBooking = user?.email === booking.guest.email
    if (user && isOwnBooking) {
      void getSavedPaymentCardsSafely(savedPaymentCardsInput)
    }

    let breakfastPackages = null
    if (shouldFetchBreakfastPackages) {
      breakfastPackages = await getPackages(packagesInput)
    }
    let savedCreditCards = null
    if (user && isOwnBooking) {
      savedCreditCards = await getSavedPaymentCardsSafely(
        savedPaymentCardsInput
      )
    }
    let ancillaryPackagesPromise = null
    if (booking.showAncillaries) {
      ancillaryPackagesPromise = getAncillaryPackages({
        fromDate,
        hotelId: hotel.operaId,
        toDate,
      })
    }

    const imageSrc =
      hotel.hotelContent.images.src ||
      additionalData.gallery?.heroImages[0]?.src ||
      hotel.galleryImages[0]?.src

    const baseUrl = env.PUBLIC_URL || "https://www.scandichotels.com"
    const promoUrl = new URL(`${baseUrl}/${lang}/`)

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

    const maskedBookingConfirmation = {
      ...bookingConfirmation,
      booking: {
        ...bookingConfirmation.booking,
        guest: {
          ...bookingConfirmation.booking.guest,
          email: maskValue.email(bookingConfirmation.booking.guest.email),
          phoneNumber: maskValue.phone(
            bookingConfirmation.booking.guest.phoneNumber ?? ""
          ),
        },
      },
    } satisfies BookingConfirmation

    const maskedUser =
      user && isOwnBooking
        ? ({
            ...user,
            email: maskValue.email(user.email),
            phoneNumber: maskValue.phone(user.phoneNumber ?? ""),
          } satisfies SafeUser)
        : null

    hotel.specialAlerts = filterOverlappingDates(
      hotel.specialAlerts,
      dt(fromDate),
      dt(toDate)
    )

    return (
      <MyStayProvider
        bookingConfirmation={maskedBookingConfirmation}
        breakfastPackages={breakfastPackages}
        lang={lang}
        linkedReservationsPromise={linkedReservationsPromise}
        refId={booking.refId}
        roomCategories={roomCategories}
        savedCreditCards={savedCreditCards}
        isLoggedIn={isLoggedIn}
      >
        <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={maskedUser}
                savedCreditCards={savedCreditCards}
              />
            )}

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

            <BookingSummary hotel={hotel} />
            {!isWebview && (
              <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>
      </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>
  )
}
