import { metrics } from "@opentelemetry/api"

import { Lang } from "@/constants/languages"
import { baseUrls } from "@/constants/routes/baseUrls"
import { batchRequest } from "@/lib/graphql/batchRequest"
import {
  GetDaDeEnUrlsAccountPage,
  GetFiNoSvUrlsAccountPage,
} from "@/lib/graphql/Query/AccountPage/AccountPage.graphql"
import {
  GetDaDeEnUrlsCollectionPage,
  GetFiNoSvUrlsCollectionPage,
} from "@/lib/graphql/Query/CollectionPage/CollectionPage.graphql"
import {
  GetDaDeEnUrlsContentPage,
  GetFiNoSvUrlsContentPage,
} from "@/lib/graphql/Query/ContentPage/ContentPage.graphql"
import {
  GetDaDeEnUrlsCurrentBlocksPage,
  GetFiNoSvUrlsCurrentBlocksPage,
} from "@/lib/graphql/Query/Current/LanguageSwitcher.graphql"
import {
  GetDaDeEnUrlsHotelPage,
  GetFiNoSvUrlsHotelPage,
} from "@/lib/graphql/Query/HotelPage/HotelPage.graphql"
import {
  GetDaDeEnUrlsLoyaltyPage,
  GetFiNoSvUrlsLoyaltyPage,
} from "@/lib/graphql/Query/LoyaltyPage/LoyaltyPage.graphql"
import { internalServerError } from "@/server/errors/trpc"
import { publicProcedure, router } from "@/server/trpc"

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

import { validateLanguageSwitcherData } from "./output"
import { languageSwitcherAffix } from "./utils"

import type {
  LanguageSwitcherData,
  LanguageSwitcherQueryDataRaw,
} from "@/types/requests/languageSwitcher"
import { PageTypeEnum } from "@/types/requests/pageType"

interface LanguageSwitcherVariables {
  contentType: string
  uid: string
}

const meter = metrics.getMeter("trpc.contentstack.languageSwitcher")
const getLanguageSwitcherCounter = meter.createCounter(
  "trpc.contentstack.languageSwitcher.get"
)
const getLanguageSwitcherSuccessCounter = meter.createCounter(
  "trpc.contentstack.languageSwitcher.get-success"
)
const getLanguageSwitcherFailCounter = meter.createCounter(
  "trpc.contentstack.languageSwitcher.get-fail"
)

async function getLanguageSwitcher(options: LanguageSwitcherVariables) {
  const variables = { uid: options.uid }
  const tagsDaDeEn = [
    generateTag(Lang.da, options.uid, languageSwitcherAffix),
    generateTag(Lang.de, options.uid, languageSwitcherAffix),
    generateTag(Lang.en, options.uid, languageSwitcherAffix),
  ]
  const tagsFiNoSv = [
    generateTag(Lang.fi, options.uid, languageSwitcherAffix),
    generateTag(Lang.no, options.uid, languageSwitcherAffix),
    generateTag(Lang.sv, options.uid, languageSwitcherAffix),
  ]
  let daDeEnDocument = null
  let fiNoSvDocument = null
  switch (options.contentType) {
    case PageTypeEnum.accountPage:
      daDeEnDocument = GetDaDeEnUrlsAccountPage
      fiNoSvDocument = GetFiNoSvUrlsAccountPage
      break
    case PageTypeEnum.currentBlocksPage:
      daDeEnDocument = GetDaDeEnUrlsCurrentBlocksPage
      fiNoSvDocument = GetFiNoSvUrlsCurrentBlocksPage
      break
    case PageTypeEnum.loyaltyPage:
      daDeEnDocument = GetDaDeEnUrlsLoyaltyPage
      fiNoSvDocument = GetFiNoSvUrlsLoyaltyPage
      break
    case PageTypeEnum.hotelPage:
      daDeEnDocument = GetDaDeEnUrlsHotelPage
      fiNoSvDocument = GetFiNoSvUrlsHotelPage
      break
    case PageTypeEnum.contentPage:
      daDeEnDocument = GetDaDeEnUrlsContentPage
      fiNoSvDocument = GetFiNoSvUrlsContentPage
      break
    case PageTypeEnum.collectionPage:
      daDeEnDocument = GetDaDeEnUrlsCollectionPage
      fiNoSvDocument = GetFiNoSvUrlsCollectionPage
      break
    default:
      console.error(`type: [${options.contentType}]`)
      console.error(`Trying to get a content type that is not supported`)
      throw internalServerError()
  }

  if (daDeEnDocument && fiNoSvDocument) {
    return await batchRequest<LanguageSwitcherQueryDataRaw>([
      {
        document: daDeEnDocument,
        variables,
        options: {
          cache: "force-cache",
          next: {
            tags: tagsDaDeEn,
          },
        },
      },
      {
        document: fiNoSvDocument,
        variables,
        options: {
          cache: "force-cache",
          next: {
            tags: tagsFiNoSv,
          },
        },
      },
    ])
  }

  throw internalServerError()
}

export const languageSwitcherQueryRouter = router({
  get: publicProcedure.query(async ({ ctx }) => {
    if (!ctx.uid || !ctx.lang) {
      return { lang: ctx.lang, urls: baseUrls }
    }
    getLanguageSwitcherCounter.add(1, {
      uid: ctx.uid,
      lang: ctx.lang,
      contentType: ctx.contentType,
    })
    console.info(
      "contentstack.languageSwitcher start",
      JSON.stringify({
        query: {
          uid: ctx.uid,
          lang: ctx.lang,
          contentType: ctx.contentType,
        },
      })
    )
    const res = await getLanguageSwitcher({
      contentType: ctx.contentType!,
      uid: ctx.uid,
    })

    const urls = Object.keys(res.data).reduce<LanguageSwitcherData>(
      (acc, key) => {
        const item = res.data[key as Lang]
        const url = item
          ? item.web?.original_url || `/${key}${item.url}`
          : undefined

        return {
          ...acc,
          [key]: { url, isExternal: !!item?.web?.original_url },
        }
      },
      {} as LanguageSwitcherData
    )

    const validatedLanguageSwitcherData =
      validateLanguageSwitcherData.safeParse(urls)

    if (!validatedLanguageSwitcherData.success) {
      getLanguageSwitcherFailCounter.add(1, {
        uid: ctx.uid,
        lang: ctx.lang,
        contentType: ctx.contentType,
        error_type: "validation_error",
        error: JSON.stringify(validatedLanguageSwitcherData.error),
      })
      console.error(
        "contentstack.languageSwitcher validation error",
        JSON.stringify({
          query: {
            uid: ctx.uid,
            lang: ctx.lang,
            contentType: ctx.contentType,
          },
          error: validatedLanguageSwitcherData.error,
        })
      )
      return null
    }
    getLanguageSwitcherSuccessCounter.add(1, {
      uid: ctx.uid,
      lang: ctx.lang,
      contentType: ctx.contentType,
    })
    console.info(
      "contentstack.languageSwitcher success",
      JSON.stringify({
        query: {
          uid: ctx.uid,
          lang: ctx.lang,
          contentType: ctx.contentType,
        },
      })
    )
    return {
      lang: ctx.lang,
      urls,
    }
  }),
})
