import {
  GetAccountPage,
  GetAccountPageRefs,
} from "@/lib/graphql/Query/AccountPage.graphql"
import { request } from "@/lib/graphql/request"
import { internalServerError, notFound } from "@/server/errors/trpc"
import { contentstackProcedure, router } from "@/server/trpc"

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

import { removeEmptyObjects } from "../../utils"
import {
  type AccountPage,
  AccountPageRefsDataRaw,
  validateAccountPageRefsSchema,
  validateAccountPageSchema,
} from "./output"
import { getConnections } from "./utils"

import { ContentEntries } from "@/types/components/myPages/myPage/enums"
import { Embeds } from "@/types/requests/embeds"
import { Edges } from "@/types/requests/utils/edges"
import { RTEDocument } from "@/types/rte/node"

export const accountPageQueryRouter = router({
  get: contentstackProcedure.query(async ({ ctx }) => {
    const { lang, uid } = ctx

    const refsResponse = await request<AccountPageRefsDataRaw>(
      GetAccountPageRefs,
      {
        locale: lang,
        uid,
      },
      {
        next: {
          tags: [generateRefsResponseTag(lang, uid)],
        },
      }
    )

    if (!refsResponse.data) {
      throw notFound(refsResponse)
    }

    // Remove empty objects from a fetched content type. Needed since
    // Contentstack returns empty objects for all non queried blocks in modular blocks.
    // This is an ongoing support case in Contentstack, ticker number #00031579
    const cleanedData = removeEmptyObjects(refsResponse.data)

    const validatedAccountPageRefs =
      validateAccountPageRefsSchema.safeParse(cleanedData)
    if (!validatedAccountPageRefs.success) {
      throw internalServerError(validatedAccountPageRefs.error)
    }

    const connections = getConnections(validatedAccountPageRefs.data)

    const tags = [
      generateTags(lang, connections),
      generateTag(lang, validatedAccountPageRefs.data.account_page.system.uid),
    ].flat()

    const response = await request<AccountPageRefsDataRaw>(
      GetAccountPage,
      {
        locale: lang,
        uid,
      },
      { next: { tags } }
    )

    if (!response.data) {
      throw notFound(response)
    }

    const validatedAccountPage = validateAccountPageSchema.safeParse(
      response.data
    )

    if (!validatedAccountPage.success) {
      throw internalServerError(validatedAccountPage.error)
    }

    // TODO: Make returned data nicer
    const content = validatedAccountPage.data.account_page.content.map(
      (block) => {
        switch (block.__typename) {
          case ContentEntries.AccountPageContentDynamicContent:
            return block
          case ContentEntries.AccountPageContentShortcuts:
            return {
              ...block,
              shortcuts: {
                ...block.shortcuts,
                shortcuts: block.shortcuts.shortcuts.map((shortcut) => ({
                  text: shortcut.text,
                  openInNewTab: shortcut.open_in_new_tab,
                  ...shortcut.linkConnection.edges[0].node,
                  url:
                    shortcut.linkConnection.edges[0].node.original_url ||
                    `/${shortcut.linkConnection.edges[0].node.system.locale}${shortcut.linkConnection.edges[0].node.url}`,
                })),
              },
            }
          case ContentEntries.AccountPageContentTextContent:
            return {
              ...block,
              text_content: {
                content: {
                  json: block.text_content.content.json as RTEDocument,
                  embedded_itemsConnection: block.text_content.content
                    .embedded_itemsConnection as Edges<Embeds>,
                },
              },
            }
          default:
            return null
        }
      }
    )

    const accountPage = {
      ...validatedAccountPage.data.account_page,
      content,
    } as AccountPage

    return accountPage
  }),
})
