import type { AcceptedLanguages } from '@payloadcms/translations'
import type { ImportMap, LanguageOptions, SanitizedConfig, ServerFunctionClient } from 'payload'

import { rtlLanguages } from '@payloadcms/translations'
import { ProgressBar, RootProvider } from '@payloadcms/ui'
import { getClientConfig } from '@payloadcms/ui/utilities/getClientConfig'
import { cookies as nextCookies } from 'next/headers.js'
import React from 'react'

import { getNavPrefs } from '../../elements/Nav/getNavPrefs.js'
import { getRequestTheme } from '../../utilities/getRequestTheme.js'
import { initReq } from '../../utilities/initReq.js'
import { checkDependencies } from './checkDependencies.js'
import { NestProviders } from './NestProviders.js'

import '@payloadcms/ui/scss/app.scss'

export const metadata = {
  description: 'Generated by Next.js',
  title: 'Next.js',
}

export const RootLayout = async ({
  children,
  config: configPromise,
  htmlProps = {},
  importMap,
  serverFunction,
}: {
  readonly children: React.ReactNode
  readonly config: Promise<SanitizedConfig>
  readonly htmlProps?: React.HtmlHTMLAttributes<HTMLHtmlElement>
  readonly importMap: ImportMap
  readonly serverFunction: ServerFunctionClient
}) => {
  checkDependencies()

  const {
    cookies,
    headers,
    languageCode,
    permissions,
    req,
    req: {
      payload: { config },
    },
  } = await initReq({ configPromise, importMap, key: 'RootLayout' })

  const theme = getRequestTheme({
    config,
    cookies,
    headers,
  })

  const dir = (rtlLanguages as unknown as AcceptedLanguages[]).includes(languageCode)
    ? 'RTL'
    : 'LTR'

  const languageOptions: LanguageOptions = Object.entries(
    config.i18n.supportedLanguages || {},
  ).reduce((acc, [language, languageConfig]) => {
    if (Object.keys(config.i18n.supportedLanguages).includes(language)) {
      acc.push({
        label: languageConfig.translations.general.thisLanguage,
        value: language,
      })
    }

    return acc
  }, [])

  async function switchLanguageServerAction(lang: string): Promise<void> {
    'use server'
    const cookies = await nextCookies()
    cookies.set({
      name: `${config.cookiePrefix || 'payload'}-lng`,
      path: '/',
      value: lang,
    })
  }

  const navPrefs = await getNavPrefs(req.payload, req.user?.id, req.user?.collection)

  const clientConfig = getClientConfig({
    config,
    i18n: req.i18n,
    importMap,
  })

  if (
    clientConfig.localization &&
    config.localization &&
    typeof config.localization.filterAvailableLocales === 'function'
  ) {
    clientConfig.localization.locales = (
      await config.localization.filterAvailableLocales({
        locales: config.localization.locales,
        req,
      })
    ).map(({ toString, ...rest }) => rest)
    clientConfig.localization.localeCodes = config.localization.locales.map(({ code }) => code)
  }

  return (
    <html
      data-theme={theme}
      dir={dir}
      lang={languageCode}
      suppressHydrationWarning={config?.admin?.suppressHydrationWarning ?? false}
      {...htmlProps}
    >
      <head>
        <style>{`@layer payload-default, payload;`}</style>
      </head>
      <body>
        <RootProvider
          config={clientConfig}
          dateFNSKey={req.i18n.dateFNSKey}
          fallbackLang={config.i18n.fallbackLanguage}
          isNavOpen={navPrefs?.open ?? true}
          languageCode={languageCode}
          languageOptions={languageOptions}
          locale={req.locale}
          permissions={permissions}
          serverFunction={serverFunction}
          switchLanguageServerAction={switchLanguageServerAction}
          theme={theme}
          translations={req.i18n.translations}
          user={req.user}
        >
          <ProgressBar />
          {Array.isArray(config.admin?.components?.providers) &&
          config.admin?.components?.providers.length > 0 ? (
            <NestProviders
              importMap={req.payload.importMap}
              providers={config.admin?.components?.providers}
              serverProps={{
                i18n: req.i18n,
                payload: req.payload,
                permissions,
                user: req.user,
              }}
            >
              {children}
            </NestProviders>
          ) : (
            children
          )}
        </RootProvider>
        <div id="portal" />
      </body>
    </html>
  )
}
