import { createSubscriptionsClient } from '@gqty/subscriptions';
// import fetch from 'cross-fetch';
import { Cache, type QueryFetcher, createClient } from 'gqty';
import { hasuraGraphqlUri, hasuraQueryTypeHeader } from './constants';
import {
  type GeneratedSchema,
  generatedSchema,
  scalarsEnumsHash,
} from './gqty';
import type { GqlAuthParam, Headers } from './types';

export type HasuraClient = ReturnType<typeof useHasuraClientInner>;

export function useHasuraClientInner(args?: Omit<GqlAuthParam, 'retries'>) {
  const $headers = args && 'headers' in args ? args.headers : undefined;
  const $fetch = (args && 'fetch' in args ? args.fetch : undefined) || fetch;
  const uri = args?.uri || hasuraGraphqlUri;

  const getHeaders = async (base?: Headers): Promise<Headers> => {
    const headers: Record<string, any> =
      ($headers && typeof $headers === 'function'
        ? await $headers()
        : $headers) || {};
    if (base) for (const key in base) headers[key] = base[key];
    if (args && 'secret' in args && args.secret) {
      headers['x-hasura-admin-secret'] = args.secret;
    } else if (args && 'accessToken' in args && args.accessToken) {
      headers.authorization = args.accessToken.startsWith('Bearer ')
        ? args.accessToken
        : `Bearer ${args.accessToken}`;
    }
    if (args?.auditUserId) headers['x-hasura-audit-user-id'] = args.auditUserId;
    return headers;
  };

  const queryFetcher: QueryFetcher = async (
    { query, variables, operationName },
    fetchOptions
  ) => {
    const headers = await getHeaders();
    if (fetchOptions?.headers) {
      for (const key in fetchOptions.headers) {
        headers[key] = fetchOptions.headers[key];
      }
    }

    // Modify "https://finalytic.hasura.app/v1/graphql" if needed
    const response = await $fetch('https://finalytic.hasura.app/v1/graphql', {
      ...fetchOptions,
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        ...headers,
      },
      body: JSON.stringify({
        query,
        variables,
        operationName,
      }),
      mode: 'cors',
    });

    const json = await response.json();
    return json; //await defaultResponseHandler(json);
  };

  const subscriptionsClient =
    args?.subscriptions === true
      ? createSubscriptionsClient({
          lazy: true,
          connectionInitPayload: async () => ({
            headers: await getHeaders({
              [hasuraQueryTypeHeader]: 'subscription',
            }),
          }),
          wsEndpoint() {
            const wsUrl = new URL(uri);
            wsUrl.protocol = wsUrl.protocol
              .replace('https', 'wss')
              .replace('http', 'ws');
            return wsUrl.href;
          },
          /*url: () => {
          },*/
        })
      : undefined;

  const cache = new Cache(undefined, {
    maxAge: 0,
    staleWhileRevalidate: 0,
    normalization: false,
  });

  const client = createClient<GeneratedSchema>({
    schema: generatedSchema,
    scalars: scalarsEnumsHash,
    //cache,
    cache,
    fetchOptions: {
      fetcher: queryFetcher,
      subscriber: subscriptionsClient,
    },
  });

  /*const client: GQtyClient<GeneratedSchema> = createClient<GeneratedSchema>({
    schema: generatedSchema,
    scalarsEnumsHash,
    queryFetcher,
    subscriptionsClient,
    normalization: args?.normalization === true,
    defaults: {
      resolved: {
        noCache: args?.cache !== true,
        retry: false,
      },
    },
    ...args,
  });*/

  return { subscriptionsClient, client };
}
