import { type NextMiddleware, NextResponse } from "next/server"

import { getUidAndContentTypeByPath } from "@/services/cms/getUidAndContentTypeByPath"
import { findLang } from "@/utils/languages"
import { removeTrailingSlash } from "@/utils/url"

import { getDefaultRequestHeaders } from "./utils"

import type { MiddlewareMatcher } from "@/types/middleware"
import { PageContentTypeEnum } from "@/types/requests/contentType"

export const middleware: NextMiddleware = async (request) => {
  const { nextUrl } = request
  const lang = findLang(nextUrl.pathname)!

  const pathWithoutTrailingSlash = removeTrailingSlash(nextUrl.pathname)

  const isPreview = request.nextUrl.pathname.includes("/preview")

  const incomingPathName = isPreview
    ? pathWithoutTrailingSlash.replace("/preview", "")
    : pathWithoutTrailingSlash

  let { contentType, uid } = await getUidAndContentTypeByPath(incomingPathName)

  const searchParams = new URLSearchParams(request.nextUrl.searchParams)

  if (!contentType || !uid) {
    // Routes to subpages we need to check if the parent of the incomingPathName exists.
    // Then we considered the incomingPathName to be a subpage. These subpages do NOT_LIVE in the CMS.
    const incomingPathNameParts = incomingPathName.split("/")

    // If the incomingPathName has 2 or more parts, it could possibly be a subpage.
    if (incomingPathNameParts.length >= 2) {
      const subpage = incomingPathNameParts.pop()
      if (subpage) {
        let { contentType: parentContentType, uid: parentUid } =
          await getUidAndContentTypeByPath(incomingPathNameParts.join("/"))

        if (parentUid) {
          switch (parentContentType) {
            case PageContentTypeEnum.hotelPage:
              // E.g. Dedicated pages for restaurant, parking etc.
              searchParams.set("subpage", subpage)
              contentType = parentContentType
              uid = parentUid
              break
            case PageContentTypeEnum.destinationCityPage:
            case PageContentTypeEnum.destinationCountryPage:
              // E.g. Active filters inside destination pages to filter hotels.
              searchParams.set("filterFromUrl", subpage)
              contentType = parentContentType
              uid = parentUid
              break
            default:
              break
          }
        }
      }
    }
  }

  if (!contentType || !uid) {
    const headers = getDefaultRequestHeaders(request)
    headers.set("x-continue", "1")

    return NextResponse.next({ headers })
  }
  const headers = getDefaultRequestHeaders(request)
  headers.set("x-uid", uid)
  headers.set("x-contenttype", contentType)

  const isCurrent = contentType ? contentType.indexOf("current") >= 0 : false

  if (isPreview) {
    searchParams.set("isPreview", "true")
    return NextResponse.rewrite(
      new URL(
        `/${lang}/${contentType}/${uid}?${searchParams.toString()}`,
        nextUrl
      ),
      {
        request: {
          headers,
        },
      }
    )
  }

  if (isCurrent) {
    const contentTypePathName = pathWithoutTrailingSlash.replace(`/${lang}`, "")
    searchParams.set("uid", uid)
    searchParams.set("uri", contentTypePathName)
    return NextResponse.rewrite(
      new URL(
        `/${lang}/current-content-page?${searchParams.toString()}`,
        nextUrl
      ),
      {
        request: {
          headers,
        },
      }
    )
  }

  return NextResponse.rewrite(
    new URL(
      `/${lang}/${contentType}/${uid}?${searchParams.toString()}`,
      nextUrl
    ),
    {
      request: {
        headers,
      },
    }
  )
}

export const matcher: MiddlewareMatcher = (request) => {
  // Do not process paths with file extension.
  // Only looking for dot might be too brute force/give false positives.
  // It works right now but adjust accordingly when new use cases/data emerges.
  const lastPathnameSegment = request.nextUrl.pathname.split("/").pop()
  return lastPathnameSegment?.indexOf(".") === -1
}
