import { redirect } from "next/navigation"

import { isDefined } from "@/server/utils"

import { getLang } from "@/i18n/serverContext"
import { cache } from "@/utils/cache"

import { serverClient } from "../server"

import type { Country } from "@/types/enums/country"
import type {
  AncillaryPackagesInput,
  BreackfastPackagesInput,
  PackagesInput,
} from "@/types/requests/packages"
import type { RoomsAvailabilityExtendedInputSchema } from "@/types/trpc/routers/hotel/availability"
import type {
  CityCoordinatesInput,
  HotelInput,
} from "@/types/trpc/routers/hotel/hotel"
import type { Lang } from "@/constants/languages"
import type { GetHotelsByCSFilterInput } from "@/server/routers/hotels/input"
import type { GetSavedPaymentCardsInput } from "@/server/routers/user/input"

export const getLocations = cache(async function getMemoizedLocations() {
  const lang = await getLang()
  const caller = await serverClient()
  return caller.hotel.locations.get({ lang })
})

export const getProfile = cache(async function getMemoizedProfile() {
  const caller = await serverClient()
  return caller.user.get()
})

export const getName = cache(async function getMemoizedName() {
  const caller = await serverClient()
  return caller.user.name()
})

export const getProfileSafely = cache(
  async function getMemoizedProfileSafely() {
    const caller = await serverClient()
    return caller.user.getSafely()
  }
)

export const getProfileWithExtendedPartnerData = cache(
  async function getMemoizedProfileWithPartnerData() {
    const caller = await serverClient()
    return caller.user.getWithExtendedPartnerData()
  }
)

export const getSavedPaymentCardsSafely = cache(
  async function getMemoizedSavedPaymentCardsSafely(
    input: GetSavedPaymentCardsInput
  ) {
    const caller = await serverClient()
    return caller.user.safePaymentCards(input)
  }
)

export const getMembershipLevel = cache(
  async function getMemoizedMembershipLevel() {
    const caller = await serverClient()
    return caller.user.membershipLevel()
  }
)

export const getMembershipLevelSafely = cache(
  async function getMemoizedMembershipLevelSafely() {
    const caller = await serverClient()
    return caller.user.safeMembershipLevel()
  }
)

export const getMembershipCards = cache(
  async function getMemoizedMembershipCards() {
    const caller = await serverClient()
    return caller.user.membershipCards()
  }
)

export const getHotelsByCSFilter = cache(async function getMemoizedHotels(
  input: GetHotelsByCSFilterInput
) {
  const caller = await serverClient()
  return caller.hotel.hotels.byCSFilter.get(input)
})

export const getHotel = cache(async function getMemoizedHotelData(
  input: HotelInput
) {
  if (!input.isCardOnlyPayment) {
    input.isCardOnlyPayment = false
  }
  const caller = await serverClient()
  return caller.hotel.get(input)
})

export const getHotelPage = cache(async function getMemoizedHotelPage() {
  const caller = await serverClient()
  return caller.contentstack.hotelPage.get()
})

export const getFooter = cache(async function getMemoizedFooter() {
  const caller = await serverClient()
  return caller.contentstack.base.footer()
})

export const getHeader = cache(async function getMemoizedHeader() {
  const caller = await serverClient()
  return caller.contentstack.base.header()
})

export const getCurrentHeader = cache(async function getMemoizedCurrentHeader(
  lang: Lang
) {
  const caller = await serverClient()
  return caller.contentstack.base.currentHeader({ lang })
})

export const getCurrentFooter = cache(async function getMemoizedCurrentFooter(
  lang: Lang
) {
  const caller = await serverClient()
  return caller.contentstack.base.currentFooter({ lang })
})

export const getSiteConfig = cache(async function getMemoizedSiteConfig(
  lang: Lang
) {
  const caller = await serverClient()
  return caller.contentstack.base.siteConfig({ lang })
})

export const getBreakfastPackages = cache(
  async function getMemoizedBreakfastPackages(input: BreackfastPackagesInput) {
    const caller = await serverClient()
    return caller.hotel.packages.breakfast(input)
  }
)

export const getAncillaryPackages = cache(
  async function getMemoizedAncillaryPackages(input: AncillaryPackagesInput) {
    const caller = await serverClient()
    return caller.hotel.packages.ancillary(input)
  }
)

export const getPackages = cache(async function getMemoizedPackages(
  input: PackagesInput
) {
  const caller = await serverClient()
  return caller.hotel.packages.get(input)
})

export const getBookingConfirmation = cache(
  async function getMemoizedBookingConfirmation(refId: string) {
    const caller = await serverClient()
    return caller.booking.get({ refId })
  }
)

export const findBooking = cache(async function getMemoizedFindBooking(
  confirmationNumber: string,
  lastName: string,
  firstName: string,
  email: string
) {
  const caller = await serverClient()
  return caller.booking.findBooking({
    confirmationNumber,
    lastName,
    firstName,
    email,
  })
})

export const getLinkedReservations = cache(
  async function getMemoizedLinkedReservations(refId: string) {
    const caller = await serverClient()
    return caller.booking.linkedReservations({
      refId,
    })
  }
)

export const getCityCoordinates = cache(
  async function getMemoizedCityCoordinates(input: CityCoordinatesInput) {
    const caller = await serverClient()
    return caller.hotel.map.city(input)
  }
)

export const getCurrentRewards = cache(
  async function getMemoizedCurrentRewards() {
    const caller = await serverClient()
    return caller.contentstack.rewards.current()
  }
)

export const getMeetingRooms = cache(
  async function getMemoizedMeetingRooms(input: {
    hotelId: string
    language: Lang
  }) {
    const caller = await serverClient()
    return caller.hotel.meetingRooms(input)
  }
)

export const getAdditionalData = cache(
  async function getMemoizedAdditionalData(input: {
    hotelId: string
    language: Lang
  }) {
    const caller = await serverClient()
    return caller.hotel.additionalData(input)
  }
)

export const getDestinationOverviewPage = cache(
  async function getMemoizedDestinationOverviewPage() {
    const caller = await serverClient()
    return caller.contentstack.destinationOverviewPage.get()
  }
)

export const getDestinationsList = cache(
  async function getMemoizedDestinationsList() {
    const caller = await serverClient()
    return caller.contentstack.destinationOverviewPage.destinations.get()
  }
)
export const getDestinationCountryPage = cache(
  async function getMemoizedDestinationCountryPage() {
    const caller = await serverClient()
    return caller.contentstack.destinationCountryPage.get()
  }
)
export const getDestinationCityPagesByCountry = cache(
  async function getMemoizedDestinationCityPagesByCountry(country: Country) {
    const caller = await serverClient()
    return caller.contentstack.destinationCountryPage.cityPages({
      country,
    })
  }
)
export const getHotelsByCountry = cache(
  async function getMemoizedHotelsByCountry(country: Country) {
    const caller = await serverClient()
    return caller.hotel.hotels.byCountry.get({
      country,
    })
  }
)
export const getHotelsByCityIdentifier = cache(
  async function getMemoizedHotelsByCityIdentifier(cityIdentifier: string) {
    const caller = await serverClient()
    return caller.hotel.hotels.byCityIdentifier.get({
      cityIdentifier,
    })
  }
)
export const getDestinationsMapData = cache(
  async function getMemoizedDestinationsMapData() {
    const caller = await serverClient()
    return caller.hotel.hotels.getDestinationsMapData()
  }
)
export const getDestinationCityPage = cache(
  async function getMemoizedDestinationCityPage() {
    const caller = await serverClient()
    return caller.contentstack.destinationCityPage.get()
  }
)

export const getStartPage = cache(async function getMemoizedStartPage() {
  const caller = await serverClient()
  return caller.contentstack.startPage.get()
})

export const getPageSettings = cache(async function getMemoizedPageSettings(
  lang: Lang
) {
  const caller = await serverClient()
  return caller.contentstack.pageSettings.get({ lang })
})

export const isBookingWidgetHidden = cache(
  async function isMemoizedBookingWidgetHidden() {
    const lang = await getLang()
    const [pageSettingsResult, siteConfigResults] = await Promise.allSettled([
      getPageSettings(lang),
      getSiteConfig(lang),
    ])

    const pageSettings =
      pageSettingsResult.status === "fulfilled"
        ? pageSettingsResult.value
        : null
    const siteConfig =
      siteConfigResults.status === "fulfilled" ? siteConfigResults.value : null

    const hideFromPageSettings =
      pageSettings?.page.settings.hide_booking_widget ?? false
    const hideFromSiteConfig = siteConfig?.bookingWidgetDisabled ?? false

    return hideFromPageSettings || hideFromSiteConfig
  }
)

export const getPageSettingsBookingCode = cache(
  async function getMemoizedPageSettingsBookingCode() {
    const lang = await getLang()
    const pageSettings = await getPageSettings(lang)
    return pageSettings?.page.settings.booking_code ?? ""
  }
)

export const getJobylonFeed = cache(async function getMemoizedJobylonFeed() {
  const caller = await serverClient()
  return caller.partner.jobylon.feed.get()
})

export const getJumpToData = cache(async function getMemoizedJumpToData() {
  const lang = await getLang()
  const caller = await serverClient()
  const [locationsResults, urlsResults] = await Promise.allSettled([
    getLocations(),
    caller.hotel.locations.urls({ lang }),
  ])

  if (
    locationsResults.status === "fulfilled" &&
    urlsResults.status === "fulfilled"
  ) {
    const locations = locationsResults.value
    const urls = urlsResults.value

    if (!locations || !urls) {
      return null
    }

    return locations
      .map((location) => {
        const { id, name, type } = location

        const isCity = type === "cities"
        const isHotel = type === "hotels"

        let url: string | undefined

        if (isCity) {
          url = urls.cities.find(
            (c) =>
              c.city &&
              location.cityIdentifier &&
              c.city === location.cityIdentifier
          )?.url
        } else if (isHotel) {
          url = urls.hotels.find(
            (h) => h.hotelId && location.id && h.hotelId === location.id
          )?.url
        }

        if (!url) {
          return null
        }

        let description = ""
        if (isCity) {
          description = location.country
        } else if (isHotel) {
          description = location.relationships.city.name
        }

        const rankingNames: string[] = [location.name]
        if (isCity) {
          if (location.cityIdentifier) {
            rankingNames.push(location.cityIdentifier)
          }
        }

        const rankingKeywords = location.keyWords || []

        return {
          id,
          displayName: name,
          type,
          description,
          url,
          rankingNames: rankingNames.map((v) => v.toLowerCase()),
          rankingKeywords: rankingKeywords.map((v) => v.toLowerCase()),
        }
      })
      .filter(isDefined)
  }

  return null
})

export const getSelectedRoomsAvailabilityEnterDetails = cache(
  async function getMemoizedSelectedRoomsAvailability(
    input: RoomsAvailabilityExtendedInputSchema
  ) {
    const caller = await serverClient()
    const result = await caller.hotel.availability.enterDetails(input)

    if (typeof result === "string") {
      redirect(result)
    }

    return result
  }
)
