import * as Sentry from "@sentry/nextjs"
import { type NextMiddleware, NextResponse } from "next/server"

import { Lang } from "@/constants/languages"

import * as authRequired from "@/middlewares/authRequired"
import * as bookingFlow from "@/middlewares/bookingFlow"
import * as cmsContent from "@/middlewares/cmsContent"
import * as currentWebLogin from "@/middlewares/currentWebLogin"
import * as currentWebLoginEmail from "@/middlewares/currentWebLoginEmail"
import * as currentWebLogout from "@/middlewares/currentWebLogout"
import * as dateQueryParams from "@/middlewares/dateQueryParams"
import * as familyAndFriends from "@/middlewares/familyAndFriends"
import * as handleAuth from "@/middlewares/handleAuth"
import * as invalidUrl from "@/middlewares/invalidUrl"
import * as legacySearchParams from "@/middlewares/legacySearchParams"
import * as myPages from "@/middlewares/myPages"
import * as redirect from "@/middlewares/redirect"
import * as sasXScandic from "@/middlewares/sasXScandic"
import * as trailingSlash from "@/middlewares/trailingSlash"
import { getDefaultRequestHeaders } from "@/middlewares/utils"
import * as webView from "@/middlewares/webView"
import { findLang } from "@/utils/languages"

export const middleware: NextMiddleware = async (request, event) => {
  // auth() overrides the request origin, we need the original for internal rewrites
  // @see getInternalNextURL()
  request.headers.set("x-sh-origin", request.nextUrl.origin)

  const headers = getDefaultRequestHeaders(request)
  const lang = findLang(request.nextUrl.pathname)

  if (!lang) {
    // Lang is required for all our middleware.
    // Without it we shortcircuit early.
    // We use middleware-error route because notFound() requires a root layout
    // which we do not want. We can move to that once all Current stuff is gone.

    // Default to English if no lang is found.
    headers.set("x-lang", Lang.en)
    return NextResponse.rewrite(
      new URL(`/${Lang.en}/middleware-error/404`, request.nextUrl),
      {
        request: {
          headers,
        },
        status: 404,
        statusText: "Not found",
      }
    )
  }

  // Note that the order of middlewares is important since that is the order they are matched by.
  const middlewares = [
    invalidUrl,
    trailingSlash,
    currentWebLogin,
    currentWebLoginEmail,
    currentWebLogout,
    authRequired,
    handleAuth,
    myPages,
    webView,
    dateQueryParams,
    legacySearchParams,
    bookingFlow,
    familyAndFriends,
    sasXScandic,
    cmsContent,
    redirect,
  ]

  try {
    for (let i = 0; i < middlewares.length; ++i) {
      const middleware = middlewares[i]

      if (middleware.matcher(request)) {
        const result = await middleware.middleware(request, event)

        const _continue = result?.headers.get("x-continue")
        if (_continue) {
          continue
        }
        // Clean up internal headers
        result?.headers.delete("x-sh-origin")

        return result
      }
    }
  } catch (e) {
    if (e instanceof NextResponse && e.status) {
      const cause = await e.json()
      console.error(`NextResponse Error in middleware`, cause)
      Sentry.captureException(cause)

      return NextResponse.rewrite(
        new URL(`/${lang}/middleware-error/${e.status}`, request.nextUrl),
        {
          request: {
            headers,
          },
          status: e.status,
          statusText: e.statusText,
        }
      )
    }

    console.error(`Error in middleware`, e)
    Sentry.captureException(e)

    return NextResponse.rewrite(
      new URL(`/${lang}/middleware-error/500`, request.nextUrl),
      {
        request: {
          headers,
        },
        status: 500,
        statusText: "Internal Server Error",
      }
    )
  }

  // Follow through with normal App router rules.
  return NextResponse.next({
    request: {
      headers,
    },
  })
}

// See "Matching Paths" below to learn more
export const config = {
  /**
   *  Copied from Clerk to protect all routes by default and handle
   *  public routes inside middleware.
   *  (https://clerk.com/docs/quickstarts/nextjs?utm_source=sponsorship&utm_medium=youtube&utm_campaign=code-with-antonio&utm_content=12-31-2023#add-authentication-to-your-app)
   */
  matcher: ["/((?!.+\\.[\\w]+$|_next|_static|.netlify|api|trpc|sitemap).*)"],
}
