
function getTrackKey(experiment: Experiment<unknown>, result: Result<unknown>) {
   return result.hashAttribute + result.hashValue + experiment.key + result.variationId;
}

function trackExperiment(
   experiment: Experiment<unknown>,
   result: Result<unknown>,
   gb: GrowthBook<AppFeatures>,
   trackedExperiments: Set<string>
) {
   if (typeof globalThis === 'undefined') {
      return;
   }
   const key = getTrackKey(experiment, result);

   if (trackedExperiments.has(experiment.key)) {
      return;
   }

   gb.setDeferredTrackingCalls([{ experiment, result }]);
   // We don't care about the return value here, we just want to fire the tracking calls
   void gb.fireDeferredTrackingCalls();
   trackedExperiments.add(key);
}

const growthbookServerClient = () => {
   const trackedExperiments = new Set<string>();

   const gb = new GrowthBook<AppFeatures>({
      ...baseSettings,
      trackingCallback: (experiment: Experiment<any>, result: Result<any>) => {
         const experimentId = experiment.key;
         const variationId = result.key;

         logger(`tracked: ${experimentId} - Bucket ${variationId} (${result.value})`, {
            experimentId,
            variationId,
            fullDetails: {
               experiment,
               result,
            },
         });

         trackGA4GrowthbookEvent({
            eventName: 'experiment_viewed',
            experimentId,
            variationId,
         });

         trackInPiwik({
            eventCategory: 'Experiment Viewed',
            eventAction: variationId,
            eventName: experimentId,
         });
      },
      onFeatureUsage(featureName, result: FeatureResult<any>) {
         if (baseSettings.onFeatureUsage) {
            baseSettings.onFeatureUsage(featureName, result);
         }

         const experiment = result.experiment;
         const experimentResult = result.experimentResult;

         if (experiment && experimentResult) {
            trackExperiment(experiment, experimentResult, gb, trackedExperiments);
         }
      },
   });

   return gb;
};