import { APP_NAME } from 'constants/global'

import { OnchainKitProvider } from '@coinbase/onchainkit'
import { sdk } from '@farcaster/miniapp-sdk'
import * as Sentry from '@sentry/react'

const sentryDsn = import.meta.env.VITE_SENTRY_DSN
if (import.meta.env.PROD && sentryDsn) {
  Sentry.init({
    dsn: sentryDsn,
    environment: import.meta.env.MODE,
    sendDefaultPii: true,
    integrations: [
      Sentry.browserTracingIntegration(),
      Sentry.replayIntegration(),
    ],
    tracesSampleRate: 1.0,
    tracePropagationTargets: ['localhost', /^https:\/\/yourserver\.io\/api/],
    replaysSessionSampleRate: 0.1,
    replaysOnErrorSampleRate: 1.0,
    enableLogs: true,
  })
}

import {
  darkTheme,
  lightTheme,
  RainbowKitProvider,
} from '@rainbow-me/rainbowkit'
import '@rainbow-me/rainbowkit/styles.css'
import spindl from '@spindl-xyz/attribution'
import { QueryClient, QueryClientProvider } from '@tanstack/react-query'
import React, { PropsWithChildren, useEffect, useMemo, Suspense } from 'react'
import ReactDOM from 'react-dom/client'
import { ReactQueryDevtools } from '@tanstack/react-query-devtools'
import { Provider } from 'react-redux'
import { RouterProvider } from 'react-router-dom'
import { router } from 'utils/createRouter'
import { config } from 'utils/createWagmiClient'
import GTM from 'utils/GTM'
import { initializeWalletConnectStorage } from 'utils/walletConnectInitializer'
import { useAccount, useBlockNumber, WagmiProvider } from 'wagmi'
import { base } from 'wagmi/chains'
import { store } from './store'
import { hashFn } from '@wagmi/core/query'

import { useAppSelector } from 'hooks'
import { selectOfflineChain } from 'services/globalSlice'
import { ThemeProvider, useTheme } from 'contexts/ThemeContext'
import './App.scss'
import './index.scss'
import './polyfills'

// defer non-critical startup work
const idle = (fn: () => void) =>
  (window as any).requestIdleCallback
    ? (window as any).requestIdleCallback(fn)
    : setTimeout(fn, 0)

const queryClient = new QueryClient({
  defaultOptions: {
    queries: {
      queryKeyHashFn: hashFn,
      retry: 1,
      refetchOnWindowFocus: false,
    },
  },
})

spindl.configure({
  sdkKey: import.meta.env.VITE_SDK_SPINDL_KEY,
})

const TxErrorWrapper: React.FC<PropsWithChildren> = ({ children }) => {
  const { address, chain } = useAccount()
  const { data: blockNumber } = useBlockNumber({ watch: false }) // avoid live subscription

  const errLog = console.error
  console.error = (...args) => {
    const err = args[0] as unknown
    const data = (args as any)[1]

    if (err && String(err).includes('contract') && data?.abi) {
      // encodeFunctionData is only needed on error; load on demand
      import('viem').then(({ encodeFunctionData }) => {
        const functionData = encodeFunctionData({
          abi: data.abi,
          functionName: data.functionName,
          args: data.args,
        })
        console.group('Transaction Error')
        console.group('Tenderly Simulation Link')
        console.log(
          `https://dashboard.tenderly.co/teller/v2/simulator/new?block=${blockNumber}&from=${address}&contractAddress=${data.contractAddress}&rawFunctionInput=${functionData}&network=${chain?.id}&blockIndex=0&gas=8000000&gasPrice=0&value=0&headerBlockNumber=&headerTimestamp=`
        )
        console.groupEnd()
        console.warn(err)
        console.groupEnd()
      })
      return
    }

    errLog(...args)
  }

  return <>{children}</>
}

const Main = () => {
  const { theme: appTheme } = useTheme()

  // memoize theme object to avoid re-creates
  const rainbowTheme = useMemo(
    () =>
      appTheme === 'dark'
        ? darkTheme({
            accentColor: '#00C5C1',
            accentColorForeground: '#0C2825',
            borderRadius: 'small',
          })
        : lightTheme({
            accentColor: '#0C2825',
            accentColorForeground: 'white',
            borderRadius: 'small',
          }),
    [appTheme]
  )

  const offlineChain = useAppSelector(selectOfflineChain)

  useEffect(() => {
    idle(() => {
      try {
        sdk.actions.ready()
      } catch {}
      // GTM after paint/idle
      try {
        if (import.meta.env.PROD) GTM.init()
      } catch {}
      // WalletConnect storage after paint/idle
      initializeWalletConnectStorage().catch(() => {})

      if ('serviceWorker' in navigator) {
        navigator.serviceWorker
          .register('/sw.js')
          .then((registration) => {
            console.log('SW registered:', registration.scope)

            registration.addEventListener('updatefound', () => {
              const newWorker = registration.installing
              if (newWorker) {
                newWorker.addEventListener('statechange', () => {
                  if (
                    newWorker.state === 'installed' &&
                    navigator.serviceWorker.controller
                  ) {
                    console.log('New SW available - reload to update')
                  }
                })
              }
            })
          })
          .catch((error) => {
            console.error('SW registration failed:', error)
          })
      }
    })

    // hide bootstrap loader ASAP after mount
    const globalLoader = document.getElementById('global-loader')
    if (globalLoader) globalLoader.style.display = 'none'
  }, [])

  return (
    <Suspense fallback={null}>
      <WagmiProvider config={config}>
        <QueryClientProvider client={queryClient}>
          <OnchainKitProvider
            apiKey={
              import.meta.env.VITE_ONCHAINKIT_API_KEY ||
              import.meta.env.VITE_CDP_CLIENT_API_KEY
            }
            chain={offlineChain ?? base}
            config={{
              appearance: {
                mode: appTheme,
                name: 'Teller',
                logo: 'https://app.teller.org/assets/teller-logo.webp',
              },
              wallet: { display: 'modal', preference: 'all' },
            }}
            miniKit={{
              enabled: true,
            }}
          >
            <RainbowKitProvider
              modalSize="compact"
              appInfo={{ appName: APP_NAME }}
              theme={rainbowTheme}
            >
              <TxErrorWrapper>
                <RouterProvider router={router} />
              </TxErrorWrapper>
            </RainbowKitProvider>
          </OnchainKitProvider>
          {import.meta.env.VITE_SHOW_TANSTACK_DEVTOOLS && (
            <ReactQueryDevtools initialIsOpen={false} />
          )}
        </QueryClientProvider>
      </WagmiProvider>
    </Suspense>
  )
}

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <Provider store={store}>
    <ThemeProvider>
      <Main />
    </ThemeProvider>
  </Provider>
)
