import { defineNuxtPlugin } from 'nuxt/app'
import type { DrupalMessage } from '~/composables/useDrupalMessages'
import type { GraphqlResponseTyped } from '#nuxt-graphql-middleware/response'
import { buildProxyRequestHeaders } from '~~/shared/request'

type GraphqlMessengerMessage = {
  type: string
  message: string
  escaped: string
  safe: string
}

/**
 * Try to extract the messages from a GraphQL query or mutation.
 */
function extractMessages(data: GraphqlResponseTyped): DrupalMessage[] {
  if (data.data && 'messengerMessages' in data.data) {
    return data.data.messengerMessages.map((v: GraphqlMessengerMessage) => {
      return {
        type: v.type,
        message: v.safe,
      }
    })
  }

  return []
}

/**
 * This is only called when performing a query or mutation from within the nuxt
 * app (e.g. not via custom server routes).
 */
export default defineNuxtPlugin({
  name: 'starterkit:graphql-plugin',
  dependsOn: ['nuxt-graphql-middleware-provide-state', 'nuxt:router'],
  setup() {
    const state = useGraphqlState()
    const { messages } = useDrupalMessages()

    const event = import.meta.server ? useRequestEvent() : undefined

    if (!state) {
      throw new Error('Missing nuxt-graphql-middleware state.')
    }

    if (import.meta.server && event) {
      state.fetchOptions.headers = buildProxyRequestHeaders(event)
    }

    state.fetchOptions.onResponse = (result) => {
      const data = result.response?._data
      if (!data) {
        return
      }

      // Extract drupal messages from every GraphQL response.
      extractMessages(data).forEach((v) => {
        const exists = messages.value.find((m) => m.message === v.message)
        if (!exists) {
          messages.value.push(v)

          if (import.meta.server) {
            // When there are messages, we have to make the whole request uncacheable.
            useCDNHeaders((v) => v.private())
          }
        }
      })

      if (import.meta.server && event) {
        useGraphqlCacheability(event, result.response?._data)
      }
    }
  },
})
