import { metrics } from "@opentelemetry/api"

import { Lang } from "@/constants/languages"
import {
  GetAccountPage,
  GetAccountPageRefs,
} from "@/lib/graphql/Query/AccountPage/AccountPage.graphql"
import { GetMyPagesMetaData } from "@/lib/graphql/Query/AccountPage/MetaData.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 { removeEmptyObjects } from "../../utils"
import { getMetaData, getResponse } from "../metadata/utils"
import {
  accountPageMetadataSchema,
  accountPageRefsSchema,
  accountPageSchema,
} from "./output"
import { getConnections } from "./utils"

import {
  TrackingChannelEnum,
  type TrackingSDKPageData,
} from "@/types/components/tracking"
import type {
  GetAccountpageMetadata,
  GetAccountPageRefsSchema,
  GetAccountPageSchema,
} from "@/types/trpc/routers/contentstack/accountPage"

const meter = metrics.getMeter("trpc.accountPage")

// OpenTelemetry metrics
const getAccountPageRefsCounter = meter.createCounter(
  "trpc.contentstack.accountPage.get"
)
const getAccountPageRefsSuccessCounter = meter.createCounter(
  "trpc.contentstack.accountPage.get-success"
)
const getAccountPageRefsFailCounter = meter.createCounter(
  "trpc.contentstack.accountPage.get-fail"
)
const getAccountPageCounter = meter.createCounter(
  "trpc.contentstack.accountPage.get"
)
const getAccountPageSuccessCounter = meter.createCounter(
  "trpc.contentstack.accountPage.get-success"
)
const getAccountPageFailCounter = meter.createCounter(
  "trpc.contentstack.accountPage.get-fail"
)

export const accountPageQueryRouter = router({
  get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
    const { lang, uid } = ctx
    getAccountPageRefsCounter.add(1, { lang, uid })
    console.info(
      "contentstack.accountPage.refs start",
      JSON.stringify({ query: { lang, uid } })
    )
    const refsResponse = await request<GetAccountPageRefsSchema>(
      GetAccountPageRefs,
      {
        locale: lang,
        uid,
      },
      {
        cache: "force-cache",
        next: {
          tags: [generateRefsResponseTag(lang, uid)],
        },
      }
    )

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

    const validatedAccountPageRefs = accountPageRefsSchema.safeParse(
      refsResponse.data
    )
    if (!validatedAccountPageRefs.success) {
      getAccountPageRefsFailCounter.add(1, {
        lang,
        uid,
        error_type: "validation_error",
        error: JSON.stringify(validatedAccountPageRefs.error),
      })
      console.error(
        "contentstack.accountPage.refs validation error",
        JSON.stringify({
          query: { lang, uid },
          error: validatedAccountPageRefs.error,
        })
      )
      return null
    }

    const connections = getConnections(validatedAccountPageRefs.data)

    const tags = [
      generateTagsFromSystem(lang, connections),
      generateTag(lang, validatedAccountPageRefs.data.account_page.system.uid),
    ].flat()
    getAccountPageRefsSuccessCounter.add(1, { lang, uid, tags })
    getAccountPageCounter.add(1, { lang, uid })
    console.info(
      "contentstack.accountPage start",
      JSON.stringify({ query: { lang, uid } })
    )
    const response = await request<GetAccountPageSchema>(
      GetAccountPage,
      {
        locale: lang,
        uid,
      },
      {
        cache: "force-cache",
        next: {
          tags,
        },
      }
    )

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

    const validatedAccountPage = accountPageSchema.safeParse(response.data)

    if (!validatedAccountPage.success) {
      getAccountPageFailCounter.add(1, {
        lang,
        uid,
        error_type: "validation_error",
        error: JSON.stringify(validatedAccountPage.error),
      })
      console.error(
        "contentstack.accountPage validation error",
        JSON.stringify({
          query: { lang, uid },
          error: validatedAccountPage.error,
        })
      )
      return null
    }
    getAccountPageSuccessCounter.add(1, { lang, uid })
    console.info(
      "contentstack.accountPage success",
      JSON.stringify({ query: { lang, uid } })
    )

    const parsedtitle = response.data.account_page.title
      .replaceAll(" ", "")
      .toLowerCase()

    const tracking: TrackingSDKPageData = {
      pageId: validatedAccountPage.data.account_page.system.uid,
      lang: validatedAccountPage.data.account_page.system.locale as Lang,
      publishedDate: validatedAccountPage.data.account_page.system.updated_at,
      createdDate: validatedAccountPage.data.account_page.system.created_at,
      channel: TrackingChannelEnum["scandic-friends"],
      pageType: `member${parsedtitle}page`,
    }

    return {
      accountPage: validatedAccountPage.data.account_page,
      tracking,
    }
  }),
  metadata: router({
    get: contentstackExtendedProcedureUID.query(async ({ ctx }) => {
      const variables = {
        locale: ctx.lang,
        uid: ctx.uid,
      }
      const response = await getResponse<GetAccountpageMetadata>(
        GetMyPagesMetaData,
        variables
      )

      const validatedMetadata = accountPageMetadataSchema.safeParse(
        response.data
      )

      if (!validatedMetadata.success) {
        console.error(
          `Failed to validate My Page MetaData Data - (uid: ${variables.uid})`
        )
        console.error(validatedMetadata.error)
        return null
      }

      return getMetaData(validatedMetadata.data.account_page)
    }),
  }),
})
