import "server-only"

import deepmerge from "deepmerge"

import { request } from "./request"

import type { BatchRequestDocument } from "graphql-request"

import type { Data } from "@/types/request"

function arrayMerge(
  target: any[],
  source: any[],
  options: deepmerge.ArrayMergeOptions | undefined
) {
  const destination = target.slice()
  source.forEach((item, index) => {
    if (typeof destination[index] === "undefined") {
      destination[index] = options?.cloneUnlessOtherwiseSpecified(item, options)
    } else if (options?.isMergeableObject(item)) {
      destination[index] = deepmerge(target[index], item, options)
    } else if (target.indexOf(item) === -1) {
      destination.push(item)
    }
  })
  return destination
}

export async function batchRequest<T>(
  queries: (BatchRequestDocument & { options?: RequestInit })[]
): Promise<Data<T>> {
  try {
    const response = await Promise.allSettled(
      queries.map((query) =>
        request<T>(query.document, query.variables, query.options)
      )
    )

    let data = {} as T
    const reasons: PromiseRejectedResult["reason"][] = []
    response.forEach((res) => {
      if (res.status === "fulfilled") {
        data = deepmerge(data, res.value.data, { arrayMerge })
      } else {
        reasons.push(res.reason)
      }
    })

    if (reasons.length) {
      reasons.forEach((reason) => {
        console.error(`Batch request failed`, reason)
      })
    }

    return { data }
  } catch (error) {
    console.error("Error in batched graphql request")
    console.error(error)
    throw new Error("Something went wrong")
  }
}
