import { useQuery } from '@tanstack/react-query';
import { useEffect, useMemo } from 'react';

import { useStores } from '@/app/(root)/AppProviders';
import { useApiClient } from '@/lib/apiClient';

type UseExperimentProps = {
  layerName: string;
  parameterName: string;
  parameterType?:
    | 'string'
    | 'boolean'
    | 'integer'
    | 'float'
    | 'array'
    | 'object';
  parameterDefault?: any;
  gatingFlagName?: string;
  suppressExperiment?: boolean;
};

export type UseExperimentValue = {
  data: string | boolean | number | null;
  error: boolean | null;
  isLoading: boolean;
};

const useExperiment = ({
  layerName,
  parameterName,
  parameterType = 'boolean',
  parameterDefault = false,
  gatingFlagName,
  suppressExperiment = false,
}: UseExperimentProps): UseExperimentValue => {
  const apiClient = useApiClient();
  const { session: sessionStore } = useStores();

  // Gating flag can be used to disable checking the experiment
  const isGatingFlagEnabled =
    !gatingFlagName || sessionStore.flags?.[gatingFlagName];

  const { data, isPending, isError, isLoading } = useQuery({
    queryKey: [
      {
        scope: 'experiment',
        layerName,
        parameterName,
        parameterType,
        parameterDefault,
      },
    ],
    queryFn: async () => {
      const response = await apiClient.POST('/api/statsig/experiment/', {
        body: {
          layer_name: layerName,
          parameter_name: parameterName,
          parameter_type: parameterType,
          parameter_default: parameterDefault,
        },
      });
      if (!response.data?.success) {
        throw new Error(
          `Failed to get experiment ${layerName} ${parameterName}`
        );
      }
      return response.data.data;
    },
    enabled: !!(
      isGatingFlagEnabled &&
      layerName &&
      parameterName &&
      !suppressExperiment
    ),
  });

  // Update experiment enabled flag in session store when we have a value from
  // the backend
  const parameterValue = data?.[parameterName];
  useEffect(() => {
    if (parameterValue != null) {
      sessionStore.setExperiment(parameterName, !!parameterValue);
    }
  }, [parameterName, parameterValue, sessionStore]);

  return useMemo(
    () => ({
      data: data?.[parameterName] ?? null,
      error: isPending ? null : isError,
      isLoading,
    }),
    [data, isPending, isError, isLoading, parameterName]
  );
};

export default useExperiment;
