import { notFound } from "next/navigation"

import {
  BookingErrorCodeEnum,
  PaymentCallbackStatusEnum,
} from "@/constants/booking"
import {
  bookingConfirmation,
  details,
} from "@/constants/routes/hotelReservation"
import { serverClient } from "@/lib/trpc/server"
import { getBooking } from "@/server/routers/booking/utils"
import { getServiceToken } from "@/server/tokenManager"

import { auth } from "@/auth"
import HandleErrorCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleErrorCallback"
import HandleSuccessCallback from "@/components/HotelReservation/EnterDetails/Payment/PaymentCallback/HandleSuccessCallback"
import { encrypt } from "@/utils/encryption"
import { isValidSession } from "@/utils/session"

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

export default async function PaymentCallbackPage(
  props: PageArgs<
    LangParams,
    {
      status?: PaymentCallbackStatusEnum
      confirmationNumber?: string
      hotel?: string
    }
  >
) {
  const searchParams = await props.searchParams
  const params = await props.params
  console.log(`[payment-callback] callback started`)
  const lang = params.lang
  const status = searchParams.status
  const confirmationNumber = searchParams.confirmationNumber

  if (!status || !confirmationNumber) {
    notFound()
  }

  let token = ""
  const session = await auth()
  if (isValidSession(session)) {
    token = session.token.access_token
  } else {
    const serviceToken = await getServiceToken()
    if (serviceToken) {
      token = serviceToken.access_token
    }
  }

  if (!token) {
    notFound()
  }

  const booking = await getBooking(confirmationNumber, params.lang, token)

  if (!booking) {
    notFound()
  }

  const { refId } = booking

  if (status === PaymentCallbackStatusEnum.Success && confirmationNumber) {
    const expire = Math.floor(Date.now() / 1000) + 60
    const sig = encrypt(expire.toString())
    const confirmationUrl = `${bookingConfirmation(lang)}?RefId=${encodeURIComponent(refId)}`
    console.log(
      `[payment-callback] rendering success callback with confirmation number: ${confirmationNumber}`
    )

    return (
      <HandleSuccessCallback
        refId={refId}
        sig={sig}
        successRedirectUrl={confirmationUrl}
      />
    )
  }

  const returnUrl = details(lang)
  const searchObject = new URLSearchParams()

  let errorMessage = undefined

  if (refId) {
    try {
      const caller = await serverClient()
      const bookingStatus = await caller.booking.status({
        refId,
      })

      const { booking } = bookingStatus

      // TODO: how to handle errors for multiple rooms?
      const error = booking.errors.find((e) => e.errorCode)

      errorMessage =
        error?.description ??
        `No error message found for booking ${confirmationNumber}, status: ${status}`

      searchObject.set(
        "errorCode",
        error
          ? error.errorCode.toString()
          : BookingErrorCodeEnum.TransactionFailed
      )
    } catch {
      console.error(
        `[payment-callback] failed to get booking status for ${confirmationNumber}, status: ${status}`
      )
      if (status === PaymentCallbackStatusEnum.Cancel) {
        searchObject.set("errorCode", BookingErrorCodeEnum.TransactionCancelled)
      }
      if (status === PaymentCallbackStatusEnum.Error) {
        searchObject.set("errorCode", BookingErrorCodeEnum.TransactionFailed)
        errorMessage = `Failed to get booking status for ${confirmationNumber}, status: ${status}`
      }
    }
  }

  return (
    <HandleErrorCallback
      returnUrl={returnUrl.toString()}
      searchObject={searchObject}
      status={status}
      errorMessage={errorMessage}
    />
  )
}
