import { metrics } from "@opentelemetry/api"

import {
  GetNavigationMyPages,
  GetNavigationMyPagesRefs,
} from "@/lib/graphql/Query/AccountPage/Navigation.graphql"
import { request } from "@/lib/graphql/request"
import { notFound } from "@/server/errors/trpc"
import { contentstackBaseProcedure, router } from "@/server/trpc"

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

import {
  type GetNavigationMyPagesData,
  type GetNavigationMyPagesRefsData,
  getNavigationSchema,
  navigationPayloadSchema,
  navigationRefsPayloadSchema,
} from "./output"
import { getConnections, mapMenuItems } from "./utils"

const meter = metrics.getMeter("trpc.navigationMyPages")
const getNavigationMyPagesRefsCounter = meter.createCounter(
  "trpc.contentstack.navigationMyPages.refs.get"
)
const getNavigationMyPagesRefsSuccessCounter = meter.createCounter(
  "trpc.contentstack.navigationMyPages.refs.get-success"
)
const getNavigationMyPagesRefsFailCounter = meter.createCounter(
  "trpc.contentstack.navigationMyPages.refs.get-fail"
)
const getNavigationMyPagesCounter = meter.createCounter(
  "trpc.contentstack.navigationMyPages.get"
)
const getNavigationMyPagesSuccessCounter = meter.createCounter(
  "trpc.contentstack.navigationMyPages.get-success"
)
const getNavigationMyPagesFailCounter = meter.createCounter(
  "trpc.contentstack.navigationMyPages.get-fail"
)

export const navigationQueryRouter = router({
  get: contentstackBaseProcedure.query(async function ({ ctx }) {
    const { lang } = ctx
    getNavigationMyPagesRefsCounter.add(1, { lang })
    console.info(
      "contentstack.myPages.navigation.refs start",
      JSON.stringify({ query: { lang } })
    )
    const refsResponse = await request<GetNavigationMyPagesRefsData>(
      GetNavigationMyPagesRefs,
      { locale: lang },
      {
        cache: "force-cache",
        next: {
          tags: [generateRefsResponseTag(lang, "navigation_my_pages")],
        },
      }
    )

    if (!refsResponse.data) {
      const notFoundError = notFound(refsResponse)
      getNavigationMyPagesRefsFailCounter.add(1, {
        lang,
        error_type: "not_found",
        error: JSON.stringify({ code: notFoundError.code }),
      })
      console.error(
        "contentstack.myPages.navigation.refs not found error",
        JSON.stringify({
          query: {
            lang,
          },
          error: { code: notFoundError.code },
        })
      )
      throw notFoundError
    }

    const validatedMyPagesNavigationRefs =
      navigationRefsPayloadSchema.safeParse(refsResponse.data)
    if (!validatedMyPagesNavigationRefs.success) {
      getNavigationMyPagesRefsFailCounter.add(1, {
        lang,
        error_type: "validation_error",
        error: JSON.stringify(validatedMyPagesNavigationRefs.error),
      })
      console.error(
        "contentstack.myPages.navigation.refs validation error",
        JSON.stringify({
          query: {
            lang,
          },
          error: validatedMyPagesNavigationRefs.error,
        })
      )
      return null
    }
    getNavigationMyPagesRefsSuccessCounter.add(1, { lang })
    console.info(
      "contentstack.myPages.navigation.refs success",
      JSON.stringify({ query: { lang } })
    )
    const connections = getConnections(validatedMyPagesNavigationRefs.data)

    const tags = [
      generateTags(lang, connections),
      generateTag(
        lang,
        validatedMyPagesNavigationRefs.data.all_navigation_my_pages.items[0]
          .system.uid
      ),
    ].flat()
    getNavigationMyPagesCounter.add(1)
    console.info(
      "contentstack.myPages.navigation start",
      JSON.stringify({ query: { lang } })
    )
    const response = await request<GetNavigationMyPagesData>(
      GetNavigationMyPages,
      { locale: lang },
      {
        cache: "force-cache",
        next: { tags },
      }
    )

    if (!response.data) {
      const notFoundError = notFound(response)
      getNavigationMyPagesFailCounter.add(1, {
        lang,
        error_type: "not_found",
        error: JSON.stringify({ code: notFoundError.code }),
      })
      console.error("contentstack.myPages.navigation not found error", {
        query: {
          lang,
        },
        error: { code: notFoundError.code },
      })
      throw notFoundError
    }

    const validatedMyPagesNavigation = navigationPayloadSchema.safeParse(
      response.data
    )
    if (!validatedMyPagesNavigation.success) {
      getNavigationMyPagesFailCounter.add(1, {
        lang,
        error_type: "validation_error",
        error: JSON.stringify(validatedMyPagesNavigation.error),
      })
      console.error(
        "contentstack.myPages.navigation.payload validation error",
        JSON.stringify({
          query: { lang },
          error: validatedMyPagesNavigation.error,
        })
      )
      return null
    }

    const menuItem =
      validatedMyPagesNavigation.data.all_navigation_my_pages.items[0]

    const nav = {
      menuItems: mapMenuItems(menuItem.menu_items),
      title: menuItem.title,
    }

    const validatedNav = getNavigationSchema.safeParse(nav)
    if (!validatedNav.success) {
      getNavigationMyPagesFailCounter.add(1, {
        lang,
        error_type: "validation_error",
        error: JSON.stringify(validatedNav.error),
      })
      console.error(
        "contentstack.myPages.navigation validation error",
        JSON.stringify({
          query: { lang },
          error: validatedNav.error,
        })
      )

      console.error(validatedNav.error)
      return null
    }
    getNavigationMyPagesSuccessCounter.add(1, { lang })
    console.info(
      "contentstack.myPages.navigation success",
      JSON.stringify({ query: { lang } })
    )
    return validatedNav.data
  }),
})
