import { Suspense, useEffect } from "react";
import {
	AppProps,
	ErrorBoundary,
	AuthenticationError,
	AuthorizationError,
	ErrorFallbackProps,
	RedirectError,
	Routes,
	useQueryErrorResetBoundary,
	getConfig,
	useSession,
} from "blitz";

import Sentry from "../../integrations/sentry";
import ErrorComponent from "../core/components/error-component";
import { usePanelbear } from "../core/hooks/use-panelbear";

import "app/core/styles/index.css";

const { publicRuntimeConfig } = getConfig();

export default function App({ Component, pageProps }: AppProps) {
	const session = useSession({ suspense: false });
	usePanelbear(publicRuntimeConfig.panelBear.siteId);
	useEffect(() => {
		if (session.userId) {
			Sentry.setUser({
				id: session.userId,
				orgId: session.orgId,
			});
		}
	}, [session]);

	const getLayout = Component.getLayout || ((page) => page);

	return (
		<ErrorBoundary
			onError={(error, componentStack) =>
				Sentry.captureException(error, { contexts: { react: { componentStack } } })
			}
			FallbackComponent={RootErrorFallback}
			onReset={useQueryErrorResetBoundary().reset}
		>
			{/* TODO: better default fallback */}
			<Suspense fallback={null}>{getLayout(<Component {...pageProps} />)}</Suspense>
		</ErrorBoundary>
	);
}

function RootErrorFallback({ error }: ErrorFallbackProps) {
	if (error instanceof AuthenticationError) {
		throw new RedirectError(Routes.SignIn());
	} else if (error instanceof AuthorizationError) {
		return <ErrorComponent statusCode={error.statusCode} title="Sorry, you are not authorized to access this" />;
	} else {
		return <ErrorComponent statusCode={error.statusCode || 400} title={error.message || error.name} />;
	}
}