import type { TypedDocumentNode } from "@apollo/client"
import { type DocumentNode, type ExecutionResult, execute, graphql } from "graphql"
import { getSchema } from "./schema"

const schema = getSchema()

class GraphQLError extends Error {}

export async function query<T extends TypedDocumentNode<any, any>>(
  source: string,
  variableValues: T extends TypedDocumentNode<any, infer K> ? K : never = {} as any,
): Promise<ExecutionResult<T extends TypedDocumentNode<infer K, any> ? K : never>> {
  const result = await graphql({ schema, source, variableValues })
  return result as any
}

async function executeNode<T extends TypedDocumentNode>(
  document: DocumentNode,
  variableValues: T extends TypedDocumentNode<any, infer K> ? K : never = {} as any,
): Promise<ExecutionResult<T extends TypedDocumentNode<infer K, any> ? K : never>> {
  const result = await execute({ schema, document, variableValues })
  return result as any
}
export { executeNode as execute }

export async function queryOrThrow<T extends TypedDocumentNode<any, any>>(
  source: string,
  variableValues: T extends TypedDocumentNode<any, infer K> ? K : never,
): Promise<T extends TypedDocumentNode<infer K, any> ? K : never> {
  const result = await graphql({ schema, source, variableValues })
  if (result.data) {
    return result.data as any
  } else {
    if (process.env.NODE_ENV === "development") {
      console.error(result.errors)
    }
    throw new GraphQLError(result.errors?.[0].message)
  }
}
