import { acceptLanguage } from '../../../server/accept-header'
import { denormalizePagePath } from '../../../server/denormalize-page-path'
import { detectDomainLocale } from './detect-domain-locale'
import { formatUrl } from '../router/utils/format-url'
import { normalizeLocalePath } from './normalize-locale-path'
import type { I18NConfig, DomainLocale } from '../../../server/config-shared'

interface Params {
  cookies(): { [key: string]: string }
  headers?: { [key: string]: string | string[] | undefined }
  nextConfig: { basePath?: string; i18n: I18NConfig; trailingSlash?: boolean }
  url: { hostname?: string | null; pathname: string }
}

export function getLocaleMetadata(params: Params) {
  const { i18n } = params.nextConfig
  const { cookies, headers, nextConfig, url } = params
  const path = normalizeLocalePath(url.pathname, i18n.locales)
  const domain = detectDomainLocale(i18n.domains, getHostname(url, headers))
  const defaultLocale = domain?.defaultLocale || i18n.defaultLocale
  const preferredLocale = getAcceptPreferredLocale(i18n, headers)
  return {
    path,
    domain,
    defaultLocale,
    locale: path?.detectedLocale || defaultLocale,
    redirect: getRedirect({
      locale: {
        preferred: preferredLocale,
        default: defaultLocale,
        detected:
          path?.detectedLocale ||
          domain?.defaultLocale ||
          getLocaleFromCookie(i18n, cookies) ||
          preferredLocale ||
          i18n.defaultLocale,
      },
      domain,
      nextConfig,
      url,
    }),
    trailingSlash:
      url.pathname !== '/'
        ? url.pathname.endsWith('/')
        : nextConfig.trailingSlash,
  }
}

function getLocaleFromCookie(
  i18n: I18NConfig,
  cookies: () => { [key: string]: string }
) {
  const nextLocale = cookies()?.NEXT_LOCALE?.toLowerCase()
  return nextLocale
    ? i18n.locales.find((locale) => nextLocale === locale.toLowerCase())
    : undefined
}

function getAcceptPreferredLocale(
  i18n: I18NConfig,
  headers?: { [key: string]: string | string[] | undefined }
) {
  const value = headers?.['accept-language']
  if (i18n.localeDetection !== false && value && !Array.isArray(value)) {
    try {
      return acceptLanguage(value, i18n.locales)
    } catch (err) {}
  }
}

function getHostname(
  parsed: { hostname?: string | null },
  headers?: { [key: string]: string | string[] | undefined }
) {
  return ((!Array.isArray(headers?.host) && headers?.host) || parsed.hostname)
    ?.split(':')[0]
    .toLowerCase()
}

function getRedirect({
  domain,
  locale,
  nextConfig,
  url,
}: {
  domain?: DomainLocale
  locale: { default: string; detected: string; preferred?: string }
  nextConfig: { basePath?: string; i18n: I18NConfig; trailingSlash?: boolean }
  url: { hostname?: string | null; pathname: string }
}) {
  const isRootPath = denormalizePagePath(url.pathname) === '/'
  if (nextConfig.i18n.localeDetection !== false && isRootPath) {
    const preferredDomain = detectDomainLocale(
      nextConfig.i18n.domains,
      undefined,
      locale.preferred
    )

    if (domain && preferredDomain) {
      const isPDomain = preferredDomain.domain === domain.domain
      const isPLocale = preferredDomain.defaultLocale === locale.preferred
      if (!isPDomain || !isPLocale) {
        const scheme = `http${preferredDomain.http ? '' : 's'}`
        const rlocale = isPLocale ? '' : locale.preferred
        return `${scheme}://${preferredDomain.domain}/${rlocale}`
      }
    }

    if (locale.detected.toLowerCase() !== locale.default.toLowerCase()) {
      return formatUrl({
        ...url,
        pathname: `${nextConfig.basePath || ''}/${locale.detected}`,
      })
    }
  }
}
