import { cache } from "react"

import {
  GetMyPagesBreadcrumbs,
  GetMyPagesBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/AccountPage.graphql"
import {
  GetCampaignPageBreadcrumbs,
  GetCampaignPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/CampaignPage.graphql"
import {
  GetCollectionPageBreadcrumbs,
  GetCollectionPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/CollectionPage.graphql"
import {
  GetContentPageBreadcrumbs,
  GetContentPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/ContentPage.graphql"
import {
  GetDestinationCityPageBreadcrumbs,
  GetDestinationCityPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/DestinationCityPage.graphql"
import {
  GetDestinationCountryPageBreadcrumbs,
  GetDestinationCountryPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/DestinationCountryPage.graphql"
import {
  GetDestinationOverviewPageBreadcrumbs,
  GetDestinationOverviewPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/DestinationOverviewPage.graphql"
import {
  GetHotelPageBreadcrumbs,
  GetHotelPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/HotelPage.graphql"
import {
  GetLoyaltyPageBreadcrumbs,
  GetLoyaltyPageBreadcrumbsRefs,
} from "@/lib/graphql/Query/Breadcrumbs/LoyaltyPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { createCounter } from "@/server/telemetry"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"

import { generateRefsResponseTag } from "@/utils/generateTag"

import { breadcrumbsRefsSchema, breadcrumbsSchema } from "./output"
import { getTags } from "./utils"

import { PageContentTypeEnum } from "@/types/requests/contentType"
import type {
  BreadcrumbsRefsSchema,
  RawBreadcrumbsSchema,
} from "@/types/trpc/routers/contentstack/breadcrumbs"
import type { Lang } from "@/constants/languages"

interface BreadcrumbsPageData<T> {
  dataKey: keyof T
  refQuery: string
  query: string
}

const getBreadcrumbs = cache(async function fetchMemoizedBreadcrumbs<T>(
  { dataKey, refQuery, query }: BreadcrumbsPageData<T>,
  { uid, lang }: { uid: string; lang: Lang }
) {
  const getBreadcrumbsRefsCounter = createCounter(
    "trpc.contentstack",
    "breadcrumbs.get.refs"
  )
  const metricsGetBreadcrumbsRefs = getBreadcrumbsRefsCounter.init({
    lang,
    uid,
  })

  metricsGetBreadcrumbsRefs.start()

  const refsResponse = await request<{ [K in keyof T]: BreadcrumbsRefsSchema }>(
    refQuery,
    { locale: lang, uid },
    {
      key: generateRefsResponseTag(lang, uid, "breadcrumbs"),
      ttl: "max",
    }
  )

  const validatedRefsData = breadcrumbsRefsSchema.safeParse(
    refsResponse.data[dataKey]
  )

  if (!validatedRefsData.success) {
    metricsGetBreadcrumbsRefs.validationError(validatedRefsData.error)
    return []
  }

  metricsGetBreadcrumbsRefs.success()

  const tags = getTags(validatedRefsData.data, lang)

  const getBreadcrumbsCounter = createCounter(
    "trpc.contentstack",
    "breadcrumbs.get"
  )
  const metricsGetBreadcrumbs = getBreadcrumbsCounter.init({
    lang,
    uid,
  })

  metricsGetBreadcrumbs.start()

  const response = await request<T>(
    query,
    { locale: lang, uid },
    {
      key: tags,
      ttl: "max",
    }
  )

  if (!response.data) {
    const notFoundError = notFound(response)
    metricsGetBreadcrumbs.noDataError()
    throw notFoundError
  }

  const validatedBreadcrumbs = breadcrumbsSchema.safeParse(
    response.data[dataKey]
  )

  if (!validatedBreadcrumbs.success) {
    metricsGetBreadcrumbs.validationError(validatedBreadcrumbs.error)
    return []
  }

  metricsGetBreadcrumbs.success()

  return validatedBreadcrumbs.data
})

export const breadcrumbsQueryRouter = router({
  get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
    const variables = {
      lang: ctx.lang,
      uid: ctx.uid,
    }

    switch (ctx.contentType) {
      case PageContentTypeEnum.accountPage:
        return await getBreadcrumbs<{
          account_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "account_page",
            refQuery: GetMyPagesBreadcrumbsRefs,
            query: GetMyPagesBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.campaignPage:
        return await getBreadcrumbs<{
          campaign_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "campaign_page",
            refQuery: GetCampaignPageBreadcrumbsRefs,
            query: GetCampaignPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.collectionPage:
        return await getBreadcrumbs<{
          collection_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "collection_page",
            refQuery: GetCollectionPageBreadcrumbsRefs,
            query: GetCollectionPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.contentPage:
        return await getBreadcrumbs<{
          content_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "content_page",
            refQuery: GetContentPageBreadcrumbsRefs,
            query: GetContentPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.destinationOverviewPage:
        return await getBreadcrumbs<{
          destination_overview_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "destination_overview_page",
            refQuery: GetDestinationOverviewPageBreadcrumbsRefs,
            query: GetDestinationOverviewPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.destinationCountryPage:
        return await getBreadcrumbs<{
          destination_country_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "destination_country_page",
            refQuery: GetDestinationCountryPageBreadcrumbsRefs,
            query: GetDestinationCountryPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.destinationCityPage:
        return await getBreadcrumbs<{
          destination_city_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "destination_city_page",
            refQuery: GetDestinationCityPageBreadcrumbsRefs,
            query: GetDestinationCityPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.hotelPage:
        return await getBreadcrumbs<{
          hotel_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "hotel_page",
            refQuery: GetHotelPageBreadcrumbsRefs,
            query: GetHotelPageBreadcrumbs,
          },
          variables
        )
      case PageContentTypeEnum.loyaltyPage:
        return await getBreadcrumbs<{
          loyalty_page: RawBreadcrumbsSchema
        }>(
          {
            dataKey: "loyalty_page",
            refQuery: GetLoyaltyPageBreadcrumbsRefs,
            query: GetLoyaltyPageBreadcrumbs,
          },
          variables
        )
      default:
        return []
    }
  }),
})
