import { type NextRequest, NextResponse } from "next/server"
import { AuthError } from "next-auth"

import { Lang } from "@/constants/languages"
import { env } from "@/env/server"
import { internalServerError } from "@/server/errors/next"
import { getPublicURL } from "@/server/utils"

import { signIn } from "@/auth"

export async function GET(
  request: NextRequest,
  context: { params: Promise<{ lang: Lang }> }
) {
  const contextParams = await context.params
  const publicURL = getPublicURL(request)

  let redirectHeaders: Headers | undefined = undefined
  let redirectTo: string

  const returnUrl = request.headers.get("x-returnurl")
  const isSeamless = request.headers.get("x-login-source") === "seamless"
  const isMFA = request.headers.get("x-login-source") === "mfa"
  const isSeamlessMagicLink =
    request.headers.get("x-login-source") === "seamless-magiclink"

  console.log(
    `[login] source: ${request.headers.get("x-login-source") || "normal"}`
  )

  const redirectToCookieValue = request.cookies.get("redirectTo")?.value // Cookie gets set by authRequired middleware
  const redirectToSearchParamValue =
    request.nextUrl.searchParams.get("redirectTo")
  const redirectToFallback = "/"

  console.log(`[login] redirectTo cookie value: ${redirectToCookieValue}`)
  console.log(
    `[login] redirectTo search param value: ${redirectToSearchParamValue}`
  )

  if (isSeamless || isSeamlessMagicLink || isMFA) {
    if (returnUrl) {
      redirectTo = returnUrl
    } else {
      console.log(
        `[login] missing returnUrl, using fallback: ${redirectToFallback}`
      )
      redirectTo = redirectToFallback
    }
  } else {
    redirectTo =
      redirectToCookieValue || redirectToSearchParamValue || redirectToFallback

    // Make relative URL to absolute URL
    if (redirectTo.startsWith("/")) {
      console.log(`[login] make redirectTo absolute, from ${redirectTo}`)
      redirectTo = new URL(redirectTo, publicURL).href
      console.log(`[login] make redirectTo absolute, to ${redirectTo}`)
    }

    // Clean up cookie from authRequired middleware
    redirectHeaders = new Headers()
    redirectHeaders.append(
      "set-cookie",
      "redirectTo=; Expires=Thu, 01 Jan 1970 00:00:00 UTC; Path=/; HttpOnly; SameSite=Lax"
    )

    try {
      // Initiate the seamless login flow
      let redirectUrlValue
      switch (contextParams.lang) {
        case Lang.da:
          redirectUrlValue = env.SEAMLESS_LOGIN_DA
          break
        case Lang.de:
          redirectUrlValue = env.SEAMLESS_LOGIN_DE
          break
        case Lang.en:
          redirectUrlValue = env.SEAMLESS_LOGIN_EN
          break
        case Lang.fi:
          redirectUrlValue = env.SEAMLESS_LOGIN_FI
          break
        case Lang.no:
          redirectUrlValue = env.SEAMLESS_LOGIN_NO
          break
        case Lang.sv:
          redirectUrlValue = env.SEAMLESS_LOGIN_SV
          break
      }
      const redirectUrl = new URL(redirectUrlValue)
      console.log(`[login] creating redirect to seamless login: ${redirectUrl}`)
      redirectUrl.searchParams.set("returnurl", redirectTo)
      console.log(
        `[login] returnurl for seamless login: ${redirectUrl.searchParams.get("returnurl")}`
      )
      redirectTo = redirectUrl.toString()

      /** Set cookie with redirect Url to appropriately redirect user when using magic link login */
      redirectHeaders.append(
        "set-cookie",
        "magicLinkRedirectTo=" +
          redirectTo +
          "; Max-Age=300; Path=/; HttpOnly; SameSite=Lax"
      )
    } catch (e) {
      console.error(
        "[login] unable to create URL for seamless login, proceeding without it.",
        e
      )
    }
  }

  try {
    console.log(`[login] final redirectUrl: ${redirectTo}`)

    /** Record<string, any> is next-auth typings */
    const params: Record<string, any> = {
      ui_locales: contextParams.lang,
      scope: [
        "openid",
        "profile",
        "booking",
        "profile_link",
        "profile_matchtier",
        "availability",
      ],
      /**
       * The `acr_values` param is used to make Curity display the proper login
       * page for Scandic. Without the parameter Curity presents some choices
       * to the user which we do not want.
       */
      acr_values: "urn:com:scandichotels:scandic",

      /**
       * Both of the below two params are required to send for initiating login as well
       * because user might choose to do Email link login.
       * */
      // The `for_origin` param is used to make Curity email login functionality working.
      for_origin: publicURL,
      // This is new param set for differentiate between the Magic link login of New web and current web
      version: "2",
    }

    if (isMFA) {
      // Append profile_update scope for MFA
      params.scope.push("profile_update")
      /**
       * The below acr value is required as for New Web same Curity Client is used for MFA
       * while in current web it is being setup using different Curity Client
       */
      params.acr_values = "urn:com:scandichotels:scandic-otp"
    } else if (isSeamlessMagicLink) {
      params.acr_values = "urn:com:scandichotels:scandic-email"
    }
    params.scope = params.scope.join(" ")
    /**
     * Passing `redirect: false` to `signIn` will return the URL instead of
     * automatically redirecting to it inside of `signIn`.
     * https://github.com/nextauthjs/next-auth/blob/3c035ec/packages/next-auth/src/lib/actions.ts#L76
     */
    const redirectUrl = await signIn(
      "curity",
      {
        redirectTo,
        redirect: false,
      },
      params
    )

    if (redirectUrl) {
      const redirectOpts = {
        headers: redirectHeaders,
      }
      console.log(`[login] redirecting to: ${redirectUrl}`, redirectOpts)
      return NextResponse.redirect(redirectUrl, redirectOpts)
    } else {
      console.error(`[login] missing redirectUrl reponse from signIn()`)
    }
  } catch (error) {
    if (error instanceof AuthError) {
      console.error({ signInAuthError: error })
    } else {
      console.error({ signInError: error })
    }
  }

  return internalServerError()
}
