import { GetDestinationCityListData } from "@/lib/graphql/Query/DestinationCityPage/DestinationCityListData.graphql"
import { GetCountryPageUrls } from "@/lib/graphql/Query/DestinationCountryPage/DestinationCountryPageUrl.graphql"
import { request } from "@/lib/graphql/request"
import { createCounter } from "@/server/telemetry"

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

import { getCitiesByCountry } from "../../hotels/utils"
import { destinationCityListDataSchema } from "../destinationCityPage/output"
import { countryPageUrlsSchema } from "./output"

import { ApiCountry, type Country } from "@/types/enums/country"
import { DestinationCountryPageEnum } from "@/types/enums/destinationCountryPage"
import type { System } from "@/types/requests/system"
import type { GetDestinationCityListDataResponse } from "@/types/trpc/routers/contentstack/destinationCityPage"
import type {
  DestinationCountryPageRefs,
  GetCountryPageUrlsData,
} from "@/types/trpc/routers/contentstack/destinationCountryPage"
import type { Lang } from "@/constants/languages"

export function generatePageTags(
  validatedData: DestinationCountryPageRefs,
  lang: Lang
): string[] {
  const connections = getConnections(validatedData)
  return [
    generateTagsFromSystem(lang, connections),
    generateTag(lang, validatedData.destination_country_page.system.uid),
  ].flat()
}

export function getConnections({
  destination_country_page,
}: DestinationCountryPageRefs) {
  const connections: System["system"][] = [destination_country_page.system]
  if (destination_country_page.blocks) {
    destination_country_page.blocks.forEach((block) => {
      switch (block.__typename) {
        case DestinationCountryPageEnum.ContentStack.blocks.Accordion: {
          if (block.accordion.length) {
            connections.push(...block.accordion)
          }
          break
        }
        case DestinationCountryPageEnum.ContentStack.blocks.Content:
          {
            if (block.content.length) {
              // TS has trouble infering the filtered types
              // @ts-ignore
              connections.push(...block.content)
            }
          }
          break
      }
    })
  }
  if (destination_country_page.sidepeek_content) {
    destination_country_page.sidepeek_content.content.embedded_itemsConnection.edges.forEach(
      ({ node }) => {
        connections.push(node.system)
      }
    )
  }

  return connections
}

export async function getCityListDataByCityIdentifier(
  lang: Lang,
  cityIdentifier: string
) {
  const getCityListDataCounter = createCounter(
    "trpc.contentstack",
    "cityListData.get"
  )
  const metricsGetCityListData = getCityListDataCounter.init({
    lang,
    cityIdentifier,
  })

  metricsGetCityListData.start()

  const response = await request<GetDestinationCityListDataResponse>(
    GetDestinationCityListData,
    {
      locale: lang,
      cityIdentifier,
    },
    {
      key: generateTag(lang, `city_list_data:${cityIdentifier}`),
      ttl: "max",
    }
  )

  if (!response.data) {
    metricsGetCityListData.dataError(
      `Failed to get destination city page for cityIdentifier: ${cityIdentifier}`
    )
    return null
  }

  const validatedResponse = destinationCityListDataSchema.safeParse(
    response.data
  )

  if (!validatedResponse.success) {
    metricsGetCityListData.validationError(validatedResponse.error)
    return null
  }

  metricsGetCityListData.success()

  return validatedResponse.data
}

export async function getCityPages(
  lang: Lang,
  serviceToken: string,
  country: Country
) {
  const apiCountry = ApiCountry[lang][country]
  const cities = await getCitiesByCountry({
    countries: [apiCountry],
    lang,
    serviceToken,
  })

  const publishedCities = cities[apiCountry].filter((city) => city.isPublished)

  const cityPages = await Promise.all(
    publishedCities.map(async (city) => {
      if (!city.cityIdentifier) {
        return null
      }

      const data = await getCityListDataByCityIdentifier(
        lang,
        city.cityIdentifier
      )
      return data ? { ...data, cityName: city.name } : null
    })
  )

  return cityPages
    .flat()
    .filter((city): city is NonNullable<typeof city> => !!city)
}

export async function getCountryPageUrls(lang: Lang) {
  const getCountryPageUrlsCounter = createCounter(
    "trpc.contentstack",
    "getCountryPageUrls"
  )
  const metricsGetCountryPageUrls = getCountryPageUrlsCounter.init({ lang })

  metricsGetCountryPageUrls.start()

  const tag = `${lang}:country_page_urls`
  const response = await request<GetCountryPageUrlsData>(
    GetCountryPageUrls,
    {
      locale: lang,
    },
    {
      key: tag,
      ttl: "max",
    }
  )

  if (!response.data) {
    metricsGetCountryPageUrls.dataError(
      `Failed to get country pages for lang: ${lang}`
    )
    return []
  }

  const validatedCountryPageUrls = countryPageUrlsSchema.safeParse(
    response.data
  )

  if (!validatedCountryPageUrls.success) {
    metricsGetCountryPageUrls.validationError(validatedCountryPageUrls.error)
    return []
  }

  metricsGetCountryPageUrls.success()

  return validatedCountryPageUrls.data
}
