import { useCallback, useState, useEffect, useRef } from 'react';
import * as Sentry from '@sentry/node';
import { AppProps, NextWebVitalsMetric } from 'next/app';
import NextJSRouter, { useRouter } from 'next/router';
import Head from 'next/head';

import * as gtag from '../lib/gtag';
import { useAuth } from '../lib/hooks';
import { AuthContext } from '../components/AuthContext';
import { CrosshareAudioContext } from '../components/CrosshareAudioContext';
import { Snackbar, SnackbarProvider } from '../components/Snackbar';
import { Global } from '@emotion/react';

import '../lib/style.css';
import { colorTheme, LINK, PRIMARY } from '../lib/style';
import { BrowserWarning } from '../components/BrowserWarning';
import { i18n } from '@lingui/core';
import { initTranslation } from '../lib/translation';
import { I18nProvider } from '@lingui/react';

initTranslation(i18n);

if (process.env.NODE_ENV === 'production' && typeof Sentry !== 'undefined') {
  Sentry.init({
    dsn: process.env.NEXT_PUBLIC_SENTRY_DSN,
    release: process.env.NEXT_PUBLIC_SENTRY_RELEASE,
    ignoreErrors: [
      'ResizeObserver loop completed with undelivered notifications',
      'ResizeObserver loop limit exceeded',
      'A mutation operation was attempted on a database that did not allow mutations',
      'is not a valid value for enumeration ScrollLogicalPosition',
      'Extension context invalidated',
      'entryTypes contained only unsupported types',
      'The popup has been closed by the user before finalizing the operation',
      'SecurityError: Blocked a frame with origin "https://crosshare.org"',
      'LPContentScriptFeatures',
      'because the client is offline',
      'Object.fromEntries is not a function',
      'cancelled due to another conflicting popup being opened',
      'installations/app-offline',
      'Error: Network Error',
    ],
  });
}

export function reportWebVitals(metric: NextWebVitalsMetric) {
  console.log(metric);
  if (
    process.env.NODE_ENV !== 'production' &&
    metric.name === 'CLS' &&
    metric.value
  ) {
    console.error('NONZERO CLS ', metric.value);
  }
  gtag.event({
    action: metric.name,
    category:
      metric.label === 'web-vital' ? 'Web Vitals' : 'Next.js custom metric',
    label: metric.id,
    value: Math.round(
      metric.name === 'CLS' ? metric.value * 1000 : metric.value
    ),
    nonInteraction: true,
  });
}

// `err` is a workaround for https://github.com/vercel/next.js/issues/8592
export default function CrosshareApp({
  Component,
  pageProps,
  err,
}: AppProps & { err: Error }): JSX.Element {
  let authStatus = useAuth();
  const [loading, setLoading] = useState(false);

  if (typeof window === 'undefined') {
    authStatus = {
      loading: true,
      isAdmin: false,
      isPatron: false,
      notifications: [],
    };
  }

  const [audioContext, setAudioContext] = useState<AudioContext | null>(null);
  const initAudioContext = useCallback(() => {
    if (!audioContext) {
      const constructor =
        // eslint-disable-next-line @typescript-eslint/no-explicit-any
        window.AudioContext || (window as any).webkitAudioContext;
      setAudioContext(new constructor());
    }
  }, [audioContext, setAudioContext]);

  useEffect(() => {
    const handleStart = () => {
      setLoading(true);
    };
    const handleError = () => {
      setLoading(false);
    };
    const handleRouteChange = (url: string) => {
      setLoading(false);
      gtag.pageview(url);
    };
    NextJSRouter.events.on('routeChangeStart', handleStart);
    NextJSRouter.events.on('routeChangeComplete', handleRouteChange);
    NextJSRouter.events.on('routeChangeError', handleError);

    return () => {
      NextJSRouter.events.off('routeChangeStart', handleStart);
      NextJSRouter.events.off('routeChangeComplete', handleRouteChange);
      NextJSRouter.events.off('routeChangeError', handleError);
    };
  }, []);

  const { locale } = useRouter();

  const firstRender = useRef(true);
  if (firstRender.current) {
    firstRender.current = false;
    if (pageProps.translation) {
      i18n.load(locale || 'en', pageProps.translation);
      i18n.activate(locale || 'en');
    } else {
      i18n.activate('en');
    }
  }

  useEffect(() => {
    if (pageProps.translation && locale) {
      i18n.load(locale, pageProps.translation);
      i18n.activate(locale);
    }
  }, [locale, pageProps.translation]);

  useEffect(() => {
    const resize = () => {
      document.documentElement.style.setProperty(
        '--vh',
        `${window.innerHeight}px`
      );
    };
    resize();
    window.addEventListener('resize', resize);
    return () => {
      window.removeEventListener('resize', resize);
    };
  }, []);

  return (
    <>
      <Head>
        <title>
          Crosshare - Free Crossword Constructor and Daily Mini Crossword
          Puzzles
        </title>
        <meta
          key="og:title"
          property="og:title"
          content="Crosshare Crosswords"
        />
        <meta
          key="description"
          name="description"
          content="Crosshare is a community for crossword constructors and solvers. Each day we post a new mini crossword puzzle you can play for free."
        />
        <meta
          key="og:description"
          property="og:description"
          content="Crosshare is a community for crossword constructors and solvers. Each day we post a new mini crossword puzzle you can play for free."
        />
        <meta
          name="viewport"
          content="minimum-scale=1, initial-scale=1, width=device-width, height=device-height"
        />
        <meta property="fb:pages" content="100687178303443" />
        <meta name="twitter:card" content="summary" />
        <meta name="twitter:site" content="@crosshareapp" />
        <meta
          key="og:image"
          property="og:image"
          content="https://crosshare.org/apple-splash-1334-750.png"
        />
        <meta property="og:image:type" content="image/png" />
        <meta key="og:image:width" property="og:image:width" content="1334" />
        <meta key="og:image:height" property="og:image:height" content="750" />
        <meta
          key="og:image:alt"
          property="og:image:alt"
          content="The crosshare logo"
        />
      </Head>
      <Global
        styles={{
          html: [
            colorTheme(PRIMARY, LINK, false, false),
            {
              '@media (prefers-color-scheme: dark)': colorTheme(
                PRIMARY,
                LINK,
                true,
                false
              ),
            },
          ],
          'body.dark-mode': colorTheme(PRIMARY, LINK, true, false),
          'body.light-mode': colorTheme(PRIMARY, LINK, false, false),
        }}
      />
      <CrosshareAudioContext.Provider value={[audioContext, initAudioContext]}>
        <AuthContext.Provider value={authStatus}>
          <SnackbarProvider>
            <BrowserWarning />
            <I18nProvider i18n={i18n}>
              <Component {...pageProps} err={err} />
            </I18nProvider>
          </SnackbarProvider>
        </AuthContext.Provider>
      </CrosshareAudioContext.Provider>
      <Snackbar message="Loading..." isOpen={loading} />
    </>
  );
}