import * as Sentry from '@sentry/nextjs'
import { LOCAL_STORAGE_KEYS, PageTelemetry, posthogClient, useUser } from 'common'
import { useEffect, useRef } from 'react'
import { useConsentToast } from 'ui-patterns/consent'

import { useOrganizationsQuery } from '@/data/organizations/organizations-query'
import { useSelectedOrganizationQuery } from '@/hooks/misc/useSelectedOrganization'
import { API_URL, IS_PLATFORM } from '@/lib/constants'

const getAnonId = async (id: string) => {
  const encoder = new TextEncoder()
  const data = encoder.encode(id)
  const hashBuffer = await crypto.subtle.digest('SHA-256', data)
  const hashArray = Array.from(new Uint8Array(hashBuffer))
  const base64String = btoa(hashArray.map((byte) => String.fromCharCode(byte)).join(''))

  return base64String
}

export function Telemetry() {
  // Although this is "technically" breaking the rules of hooks
  // IS_PLATFORM never changes within a session, so this won't cause any issues
  // eslint-disable-next-line react-hooks/rules-of-hooks
  const { hasAcceptedConsent } = IS_PLATFORM ? useConsentToast() : { hasAcceptedConsent: true }

  // Get org from selected organization query because it's not
  // always available in the URL params
  const { data: organization } = useSelectedOrganizationQuery()

  const user = useUser()

  // Mirror the user's org-list length into a PostHog person property so feature
  // flags and analytics can segment by current org membership. signup_timestamp
  // is set on the same identify so flag audiences requiring both properties see
  // them together on /decide. Only fires when the value changes.
  const { data: organizations } = useOrganizationsQuery()
  const lastSentRef = useRef<{
    userId: string
    orgCount: number
    signupTimestamp?: string
  } | null>(null)
  useEffect(() => {
    if (!user?.id || !organizations) return
    const orgCount = organizations.length
    const signupTimestamp = user.created_at ?? undefined
    const last = lastSentRef.current
    if (
      last?.userId === user.id &&
      last.orgCount === orgCount &&
      last.signupTimestamp === signupTimestamp
    ) {
      return
    }
    lastSentRef.current = { userId: user.id, orgCount, signupTimestamp }
    posthogClient.identify(user.id, {
      org_count: orgCount,
      ...(signupTimestamp && { signup_timestamp: signupTimestamp }),
    })
  }, [user?.id, user?.created_at, organizations])

  useEffect(() => {
    // don't set the sentry user id if the user hasn't logged in (so that Sentry errors show null user id instead of anonymous id)
    if (!user?.id) {
      return
    }

    const setSentryId = async () => {
      let sentryUserId = localStorage.getItem(LOCAL_STORAGE_KEYS.SENTRY_USER_ID)
      if (!sentryUserId) {
        sentryUserId = await getAnonId(user?.id)
        localStorage.setItem(LOCAL_STORAGE_KEYS.SENTRY_USER_ID, sentryUserId)
      }
      Sentry.setUser({ id: sentryUserId })
    }

    // if an error happens, continue without setting a sentry id
    setSentryId().catch((e) => console.error(e))
  }, [user?.id])

  return (
    <PageTelemetry
      API_URL={API_URL}
      hasAcceptedConsent={hasAcceptedConsent}
      enabled={IS_PLATFORM}
      organizationSlug={organization?.slug}
    />
  )
}
