import { z } from "zod"

import { baseUrls } from "@/constants/routes/baseUrls"
import { findMyBooking } from "@/constants/routes/findMyBooking"
import { hotelreservation } from "@/constants/routes/hotelReservation"
import { myStay } from "@/constants/routes/myStay"
import { env } from "@/env/server"

import { attributesSchema as hotelAttributesSchema } from "../../hotels/schemas/hotel"
import { additionalDataAttributesSchema } from "../../hotels/schemas/hotel/include/additionalData"
import { imageSchema } from "../../hotels/schemas/image"
import { tempImageVaultAssetSchema } from "../schemas/imageVault"
import { systemSchema } from "../schemas/system"
import { getDescription } from "./utils/description"
import { getImage } from "./utils/image"
import { getTitle } from "./utils/title"

import type { Metadata } from "next"

import type { ImageVaultAsset } from "@/types/components/imageVault"
import { Country } from "@/types/enums/country"
import type { LanguageSwitcherData } from "@/types/requests/languageSwitcher"
import { RTETypeEnum } from "@/types/rte/enums"
import type { Lang } from "@/constants/languages"

const metaDataJsonSchema = z.object({
  children: z.array(
    z.object({
      type: z.nativeEnum(RTETypeEnum),
      children: z.array(
        z.object({
          text: z.string().optional(),
        })
      ),
    })
  ),
})

const metaDataBlocksSchema = z
  .array(
    z.object({
      content: z
        .object({
          content: z
            .object({
              json: metaDataJsonSchema,
            })
            .optional()
            .nullable(),
        })
        .optional()
        .nullable(),
    })
  )
  .optional()
  .nullable()

export const rawMetadataSchema = z.object({
  web: z
    .object({
      seo_metadata: z
        .object({
          title: z.string().nullish(),
          description: z.string().nullish(),
          noindex: z.boolean().nullish(),
          seo_image: tempImageVaultAssetSchema.nullable(),
        })
        .nullish(),
      breadcrumbs: z
        .object({
          title: z.string().nullish(),
        })
        .nullish(),
    })
    .nullish(),
  destination_settings: z
    .object({
      city_denmark: z.string().nullish(),
      city_finland: z.string().nullish(),
      city_germany: z.string().nullish(),
      city_poland: z.string().nullish(),
      city_norway: z.string().nullish(),
      city_sweden: z.string().nullish(),
      country: z.nativeEnum(Country).nullish(),
    })
    .nullish(),
  heading: z.string().nullish(),
  preamble: z.string().nullish(),
  header: z
    .object({
      heading: z.string().nullish(),
      preamble: z.string().nullish(),
      hero_image: tempImageVaultAssetSchema.nullable(),
    })
    .nullish(),
  hero_image: tempImageVaultAssetSchema.nullable(),
  images: z
    .array(z.object({ image: tempImageVaultAssetSchema }).nullish())
    .transform((images) =>
      images
        .map((image) => image?.image)
        .filter((image): image is ImageVaultAsset => !!image)
    )
    .nullish(),
  blocks: metaDataBlocksSchema,
  hotel_page_id: z.string().nullish(),
  hotelData: hotelAttributesSchema
    .pick({
      name: true,
      address: true,
      detailedFacilities: true,
      hotelContent: true,
      healthFacilities: true,
    })
    .nullish(),
  additionalHotelData: additionalDataAttributesSchema
    .pick({
      gallery: true,
      hotelParking: true,
      healthAndFitness: true,
      hotelSpecialNeeds: true,
      meetingRooms: true,
      parkingImages: true,
      accessibility: true,
      conferencesAndMeetings: true,
    })
    .nullish(),
  hotelRestaurants: z
    .array(
      z.object({
        nameInUrl: z.string().nullish(),
        elevatorPitch: z.string().nullish(),
        name: z.string().nullish(),
        content: z
          .object({
            images: z.array(imageSchema).nullish(),
          })
          .nullish(),
      })
    )
    .nullish(),
  subpageUrl: z.string().nullish(),
  destinationData: z
    .object({
      location: z.string().nullish(),
      filter: z.string().nullish(),
      filterType: z.enum(["facility", "surroundings"]).nullish(),
      hotelCount: z.number().nullish(),
      cities: z.array(z.string()).nullish(),
    })
    .nullish(),
  system: systemSchema,
})

export const metadataSchema = rawMetadataSchema.transform(async (data) => {
  const noIndex = !!data.web?.seo_metadata?.noindex

  const metadata: Metadata = {
    metadataBase: env.PUBLIC_URL ? new URL(env.PUBLIC_URL) : undefined,
    title: await getTitle(data),
    description: await getDescription(data),
    openGraph: {
      images: getImage(data),
    },
  }

  if (noIndex) {
    metadata.robots = {
      index: false,
      follow: false,
    }
  }
  return metadata
})

// Several pages are not currently routed within contentstack context.
// This function is used to generate the urls for these pages.
export function getNonContentstackUrls(lang: Lang, pathName: string) {
  if (Object.values(findMyBooking).includes(pathName)) {
    const urls: LanguageSwitcherData = {}
    return Object.entries(findMyBooking).reduce((acc, [lang, url]) => {
      acc[lang as Lang] = { url }
      return urls
    }, urls)
  }

  if (Object.values(myStay).includes(pathName)) {
    const urls: LanguageSwitcherData = {}
    return Object.entries(myStay).reduce((acc, [lang, url]) => {
      acc[lang as Lang] = { url }
      return urls
    }, urls)
  }

  if (pathName.startsWith(hotelreservation(lang))) {
    return baseUrls
  }

  return { [lang]: { url: pathName } }
}
