import type { AppProps } from 'next/app'
import type { NextPage } from 'next'
import { SessionProvider } from 'next-auth/react'
import { SWRConfig } from 'swr'
import toast, { Toaster } from 'react-hot-toast'
import { appWithTranslation } from 'next-i18next'
import { useEffect, useState, ReactElement, ReactNode } from 'react'
import { z } from 'zod'
import { ERROR_MESSAGES } from '@/lib/error-messages'
import '@/styles/globals.css'

// @ts-ignore
z.setErrorMap((issue: any, ctx: any) => {
    if (issue.code === 'too_small' && issue.type === 'string')
        return { message: ERROR_MESSAGES.minLength(issue.minimum as number) }
    if (issue.code === 'invalid_string' && issue.validation === 'email')
        return { message: ERROR_MESSAGES.email }
    return { message: ctx.defaultError }
})

const fetcher = (url: string) => fetch(url).then(r => r.json())

export type NextPageWithLayout<P = {}, IP = P> = NextPage<P, IP> & {
    getLayout?: (page: ReactElement) => ReactNode
}

type AppPropsWithLayout = AppProps & {
    Component: NextPageWithLayout
}

import { ThemeProvider } from 'next-themes'
import { ImpersonationProvider } from '@/lib/context/ImpersonationContext'

function MyApp({ Component, pageProps: { session, ...pageProps } }: AppPropsWithLayout) {
    const getLayout = Component.getLayout ?? ((page: ReactElement) => page)
    const [mounted, setMounted] = useState(false)

    useEffect(() => {
        setMounted(true)
    }, [])

    if (!mounted) {
        return <div suppressHydrationWarning />
    }

    return (
        <ThemeProvider attribute="class" defaultTheme="system" enableSystem>
            <ImpersonationProvider>
                <SessionProvider session={session}>
                    <SWRConfig value={{
                        fetcher,
                        revalidateOnFocus: false,
                        dedupingInterval: 5000,
                        errorRetryCount: 3,
                        errorRetryInterval: 2000,
                        onError: (err) => {
                            if (err.status !== 404) {
                                // Toast would show error
                            }
                        }
                    }}>
                        {getLayout(<Component {...pageProps} />)}
                        <Toaster
                            position="top-right"
                            gutter={12}
                            toastOptions={{
                                className: 'font-urbanist font-normal rounded-2xl shadow-2xl',
                                duration: 5000,
                                style: {
                                    padding: '16px 24px',
                                    fontSize: '14px',
                                },
                                success: {
                                    style: {
                                        background: '#ECFDF5',
                                        color: '#065F46',
                                        border: '1px solid #A7F3D0',
                                    },
                                    iconTheme: {
                                        primary: '#10b981',
                                        secondary: '#fff',
                                    },
                                },
                                error: {
                                    style: {
                                        background: 'var(--danger-200)',
                                        color: 'var(--text-heading)',
                                        border: 'none',
                                    },
                                    iconTheme: {
                                        primary: 'var(--text-heading)',
                                        secondary: 'var(--danger-200)',
                                    },
                                    duration: 5000,
                                },
                            }}
                        />
                    </SWRConfig>
                </SessionProvider>
            </ImpersonationProvider>
        </ThemeProvider>
    )
}

export default appWithTranslation(MyApp)
