import { metrics } from "@opentelemetry/api"

import { Lang } from "@/constants/languages"
import {
  GetLoyaltyPage,
  GetLoyaltyPageRefs,
} from "@/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { contentstackExtendedProcedureUID, router } from "@/server/trpc"

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

import { loyaltyPageRefsSchema, loyaltyPageSchema } from "./output"
import { getConnections } from "./utils"

import {
  TrackingChannelEnum,
  TrackingSDKPageData,
} from "@/types/components/tracking"
import type {
  GetLoyaltyPageRefsSchema,
  GetLoyaltyPageSchema,
} from "@/types/trpc/routers/contentstack/loyaltyPage"

const meter = metrics.getMeter("trpc.loyaltyPage")
// OpenTelemetry metrics: LoyaltyPage
const getLoyaltyPageRefsCounter = meter.createCounter(
  "trpc.contentstack.loyaltyPage.get"
)
const getLoyaltyPageRefsSuccessCounter = meter.createCounter(
  "trpc.contentstack.loyaltyPage.get-success"
)
const getLoyaltyPageRefsFailCounter = meter.createCounter(
  "trpc.contentstack.loyaltyPage.get-fail"
)
const getLoyaltyPageCounter = meter.createCounter(
  "trpc.contentstack.loyaltyPage.get"
)
const getLoyaltyPageSuccessCounter = meter.createCounter(
  "trpc.contentstack.loyaltyPage.get-success"
)
const getLoyaltyPageFailCounter = meter.createCounter(
  "trpc.contentstack.loyaltyPage.get-fail"
)

export const loyaltyPageQueryRouter = router({
  get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
    const { lang, uid } = ctx
    const metricsVariables = { lang, uid }
    const variables = { locale: lang, uid }
    getLoyaltyPageRefsCounter.add(1, metricsVariables)
    console.info(
      "contentstack.loyaltyPage.refs start",
      JSON.stringify({
        query: metricsVariables,
      })
    )
    const refsResponse = await request<GetLoyaltyPageRefsSchema>(
      GetLoyaltyPageRefs,
      variables,
      {
        cache: "force-cache",
        next: {
          tags: [generateRefsResponseTag(lang, uid)],
        },
      }
    )

    if (!refsResponse.data) {
      const notFoundError = notFound(refsResponse)
      getLoyaltyPageRefsFailCounter.add(1, {
        ...metricsVariables,
        error_type: "http_error",
        error: JSON.stringify({
          code: notFoundError.code,
        }),
      })
      console.error(
        "contentstack.loyaltyPage.refs not found error",
        JSON.stringify({
          query: metricsVariables,
          error: { code: notFoundError.code },
        })
      )
      throw notFoundError
    }

    const validatedLoyaltyPageRefs = loyaltyPageRefsSchema.safeParse(
      refsResponse.data
    )
    if (!validatedLoyaltyPageRefs.success) {
      getLoyaltyPageRefsFailCounter.add(1, {
        ...metricsVariables,
        error_type: "validation_error",
        error: JSON.stringify(validatedLoyaltyPageRefs.error),
      })
      console.error(
        "contentstack.loyaltyPage.refs validation error",
        JSON.stringify({
          query: metricsVariables,
          error: validatedLoyaltyPageRefs.error,
        })
      )
      return null
    }
    getLoyaltyPageRefsSuccessCounter.add(1, metricsVariables)
    console.info(
      "contentstack.loyaltyPage.refs success",
      JSON.stringify({
        query: metricsVariables,
      })
    )

    const connections = getConnections(validatedLoyaltyPageRefs.data)

    const tags = [
      generateTagsFromSystem(lang, connections),
      generateTag(lang, validatedLoyaltyPageRefs.data.loyalty_page.system.uid),
    ].flat()
    getLoyaltyPageCounter.add(1, metricsVariables)
    console.info(
      "contentstack.loyaltyPage start",
      JSON.stringify({
        query: metricsVariables,
      })
    )
    const response = await request<GetLoyaltyPageSchema>(
      GetLoyaltyPage,
      variables,
      {
        cache: "force-cache",
        next: { tags },
      }
    )

    if (!response.data) {
      const notFoundError = notFound(response)
      getLoyaltyPageFailCounter.add(1, {
        ...metricsVariables,
        error_type: "http_error",
        error: JSON.stringify({ code: notFoundError.code }),
      })
      console.error(
        "contentstack.loyaltyPage not found error",
        JSON.stringify({
          query: metricsVariables,
          error: { code: notFoundError.code },
        })
      )
      throw notFound(response)
    }

    const validatedLoyaltyPage = loyaltyPageSchema.safeParse(response.data)
    if (!validatedLoyaltyPage.success) {
      getLoyaltyPageFailCounter.add(1, {
        ...metricsVariables,
        error_type: "validation_error",
        error: JSON.stringify(validatedLoyaltyPage.error),
      })
      console.error(
        "contentstack.loyaltyPage validation error",
        JSON.stringify({
          query: metricsVariables,
          error: validatedLoyaltyPage.error,
        })
      )
      return null
    }

    const loyaltyPage = validatedLoyaltyPage.data.loyalty_page

    const loyaltyTrackingData: TrackingSDKPageData = {
      pageId: loyaltyPage.system.uid,
      lang: loyaltyPage.system.locale as Lang,
      publishedDate: loyaltyPage.system.updated_at,
      createdDate: loyaltyPage.system.created_at,
      channel: TrackingChannelEnum["scandic-friends"],
      pageType: "loyaltycontentpage",
    }
    getLoyaltyPageSuccessCounter.add(1, metricsVariables)
    console.info(
      "contentstack.loyaltyPage success",
      JSON.stringify({ query: metricsVariables })
    )

    // Assert LoyaltyPage type to get correct typings for RTE fields
    return {
      loyaltyPage,
      tracking: loyaltyTrackingData,
    }
  }),
})
