'use client';

import { datadogRum } from '@datadog/browser-rum';
import {
  StatsigOptions,
  StatsigProvider,
  StatsigUser,
  useClientAsyncInit,
} from '@statsig/react-bindings';
import { observer } from 'mobx-react-lite';
import { usePathname } from 'next/navigation';
import React, {
  createContext,
  useContext,
  useEffect,
  useMemo,
  useRef,
} from 'react';
import { useCookies } from 'react-cookie';

import { version as packageJsonVersion } from '@/../package.json';
import { useStores } from '@/app/(root)/AppProviders';
import { identifyUser } from '@/logging/logWebUserEvent';
import {
  initializeHomePageSegmentClient,
  initializeSegmentClient,
  updateCachedPathnameForSegment,
} from '@/logging/segmentClient';
import {
  CLIENT_STATSIG_SDK_KEY,
  HAS_LOGGED_IN_BEFORE,
} from '@/utils/constants';
import { getDeviceId } from '@/utils/device';
import { getStatsigTier } from '@/utils/environment';

export interface StatsigUserContextProps {
  userId?: string | null;
  userEmail?: string | null;
  username?: string | null;
  deviceId?: string | null;
  country?: string | null;
  postalCode?: string | null;
  latitude?: string | null;
  longitude?: string | null;
  city?: string | null;
  region?: string | null;
  forwardedFor?: string | null;
  userPlanKey?: string | null;
}

export function getStatsigUser(options: StatsigUserContextProps) {
  const {
    userId,
    userEmail,
    deviceId = getDeviceId(),
    country,
    postalCode,
    latitude,
    longitude,
    city,
    region,
    forwardedFor,
    userPlanKey,
  } = options;

  const statsigUser: StatsigUser &
    Required<Pick<StatsigUser, 'customIDs' | 'custom'>> = {
    customIDs: {
      'Anonymous ID': deviceId || '',
    },
    custom: {},
  };

  if (userId || userEmail) {
    statsigUser.userID = userId || undefined;
    statsigUser.email = userEmail || undefined;
  }

  if (country) statsigUser.country = country;
  if (postalCode) {
    statsigUser.customIDs['Postal Code'] = postalCode;
    statsigUser.custom.postal_code = postalCode;
  }
  if (latitude) {
    statsigUser.customIDs['Latitude'] = latitude;
    statsigUser.custom.latitude = latitude;
  }
  if (longitude) {
    statsigUser.customIDs['Longitude'] = longitude;
    statsigUser.custom.longitude = longitude;
  }
  if (city) {
    statsigUser.customIDs['City'] = city;
    statsigUser.custom.city = city;
  }
  if (region) {
    statsigUser.customIDs['Country Region'] = region;
    statsigUser.custom.country_region = region;
  }
  if (region && country?.toUpperCase() === 'US') {
    statsigUser.customIDs['US State'] = region;
    statsigUser.custom.us_state = region;
  }
  if (forwardedFor) {
    statsigUser.customIDs['IP Address'] = forwardedFor;
    statsigUser.custom.ip_address = forwardedFor;
  }
  if (userPlanKey) {
    statsigUser.custom.user_plan_key = userPlanKey;
  } else {
    statsigUser.custom.user_plan_key = 'free';
  }

  return statsigUser;
}

const statsigOptions: StatsigOptions = {
  environment: { tier: getStatsigTier() },
};

if (process.env.NEXT_PUBLIC_STATSIG_PROXY_URL) {
  statsigOptions.networkConfig = {
    api: process.env.NEXT_PUBLIC_STATSIG_PROXY_URL,
  };
}

export interface AnalyticsContextProps {
  country?: string | null;
  postalCode?: string | null;
  latitude?: string | null;
  longitude?: string | null;
  city?: string | null;
  region?: string | null;
  forwardedFor?: string | null;
}

export const AnalyticsContext = createContext<AnalyticsContextProps>({});

export const AnalyticsProvider: React.FC<
  React.PropsWithChildren<StatsigUserContextProps>
> = observer((props) => {
  const {
    userId: explicitUserId,
    userEmail: explicitUserEmail,
    username: explicitUsername,
    deviceId: explicitDeviceId,
    country,
    postalCode,
    latitude,
    longitude,
    city,
    region,
    forwardedFor,
    userPlanKey: explicitUserPlanKey,
  } = props;

  const { session: sessionStore } = useStores();

  const [, setCookie] = useCookies([HAS_LOGGED_IN_BEFORE]);

  const pathname = usePathname();

  const userId = explicitUserId ?? sessionStore.userId;
  const userEmail = explicitUserEmail ?? sessionStore.userEmail;
  const username = explicitUsername ?? sessionStore.username;
  const deviceId = explicitDeviceId ?? getDeviceId();
  const userPlanKey = explicitUserPlanKey ?? sessionStore.userPlanKey;
  const statsigUser = useMemo(
    () =>
      getStatsigUser({
        userId,
        userEmail,
        username,
        deviceId,
        country,
        postalCode,
        latitude,
        longitude,
        city,
        region,
        forwardedFor,
        userPlanKey,
      }),
    [
      userId,
      userEmail,
      username,
      deviceId,
      country,
      postalCode,
      latitude,
      longitude,
      city,
      region,
      forwardedFor,
      userPlanKey,
    ]
  );

  /**
   * Statsig client
   *
   * IMPORTANT: `AnalyticsProvider` MUST NOT mix calls to the other Statsig
   * React hooks, becaues they will effectively access a different client
   * instance than the one we're defining here.
   *
   * It IS safe to use `useStatsigClient` and `useGateValue` hooks in
   * downstream components, because they will be pulling the client from the
   * `StatsigProvider` that we define below.
   */
  const { client: statsigClient } = useClientAsyncInit(
    CLIENT_STATSIG_SDK_KEY,
    statsigUser,
    statsigOptions
  );

  // Set the Statsig client on the session store once we have the stable ID
  useEffect(() => {
    if (statsigClient.getContext().stableID) {
      sessionStore.setStatsigClient(statsigClient);
    }
  }, [statsigClient, sessionStore]);

  // Update Statsig user whenever the user data changes
  useEffect(() => {
    if (statsigUser.userID) {
      setCookie(HAS_LOGGED_IN_BEFORE, true, { path: '/', maxAge: 31536000 }); // 1 year expiry
    }
    statsigClient.updateUserAsync(statsigUser);
  }, [statsigClient, statsigUser, setCookie]);

  /**
   * Update cached pathname for analytics routing
   */
  useEffect(() => {
    updateCachedPathnameForSegment(pathname);
  }, [pathname]);

  /**
   * Segment clients (event logging)
   * - Standard client: 10s batch timeout for most pages
   * - Home page client: 1s batch timeout for /home page
   */
  useEffect(() => {
    const analyticsBaseUrlConfig =
      statsigClient.getDynamicConfig('analytics-base-url');

    const analyticsBaseUrl: string = analyticsBaseUrlConfig.get(
      'domain_base_fragment_url',
      ''
    );

    // Initialize both clients with same endpoint but different batch configs
    initializeSegmentClient(analyticsBaseUrl);
    initializeHomePageSegmentClient(analyticsBaseUrl);
  }, [statsigClient]);

  /**
   * User identity logging event
   */
  const lastIdentifiedUserId = useRef<string | undefined>(undefined);
  useEffect(() => {
    if (userId && userId !== lastIdentifiedUserId.current) {
      lastIdentifiedUserId.current = userId;
      identifyUser(userId);
    }
  }, [userId]);

  /**
   * DataDog realtime user metrics
   */
  useEffect(() => {
    let env = 'staging';
    if (
      process.env.NEXT_PUBLIC_API_BASE === 'https://studio-api.suno.ai' ||
      process.env.NEXT_PUBLIC_API_BASE === 'https://studio-api.prod.suno.com'
    ) {
      env = 'prod';
    }

    if (
      process.env.NEXT_PUBLIC_DD_RUM_APPLICATION_ID &&
      process.env.NEXT_PUBLIC_DD_RUM_CLIENT_TOKEN &&
      process.env.NEXT_PUBLIC_DD_RUM_SAMPLE_RATE &&
      process.env.NEXT_PUBLIC_DD_RUM_REPLAY_SAMPLE_RATE &&
      process.env.NEXT_PUBLIC_API_BASE &&
      process.env.NEXT_PUBLIC_API_BASE_ECS
    ) {
      datadogRum.init({
        applicationId: process.env.NEXT_PUBLIC_DD_RUM_APPLICATION_ID,
        clientToken: process.env.NEXT_PUBLIC_DD_RUM_CLIENT_TOKEN,
        site: 'datadoghq.com',
        service: `suno-studio-api-${env}`,
        env: env,
        version: packageJsonVersion,
        sessionSampleRate: parseInt(process.env.NEXT_PUBLIC_DD_RUM_SAMPLE_RATE),
        sessionReplaySampleRate: parseInt(
          process.env.NEXT_PUBLIC_DD_RUM_REPLAY_SAMPLE_RATE
        ),
        // sessionSampleRate: 100,
        // sessionReplaySampleRate: 100,
        trackUserInteractions: true,
        allowedTracingUrls: [
          process.env.NEXT_PUBLIC_API_BASE,
          process.env.NEXT_PUBLIC_API_BASE_ECS,
        ],
        trackResources: true,
        trackLongTasks: true,
        defaultPrivacyLevel: 'mask-user-input',
      });
    }
  }, []);

  // Initialie DataDog realtime user metrics
  useEffect(() => {
    if (datadogRum.getInitConfiguration()?.applicationId) {
      datadogRum.setUser({
        id: userId || undefined,
        email: userEmail || undefined,
        name: username || undefined,
      });
    }
  }, [userId, userEmail, username]);

  const contextValue = useMemo(
    () => ({
      country,
      postalCode,
      latitude,
      longitude,
      city,
      region,
      forwardedFor,
    }),
    [country, postalCode, latitude, longitude, city, region, forwardedFor]
  );

  return (
    <AnalyticsContext.Provider value={contextValue}>
      <StatsigProvider client={statsigClient}>{props.children}</StatsigProvider>
    </AnalyticsContext.Provider>
  );
});

export function useAnalyticsContext() {
  return useContext(AnalyticsContext);
}
