import NextAuth from "next-auth"

import { env } from "@/env/server"

import type { NextAuthConfig, User } from "next-auth"
import type { OIDCConfig } from "next-auth/providers"

const customProvider = {
  clientId: env.CURITY_CLIENT_ID_USER,
  clientSecret: env.CURITY_CLIENT_SECRET_USER,
  id: "curity",
  name: "Curity",
  type: "oidc",
  // FIXME: This is incorrect. We should not hard code this.
  //        It should be ${env.CURITY_ISSUER_USER}.
  //        This change requires sync between Curity deploy and CurrentWeb and NewWeb.
  issuer: "https://scandichotels.com",
  authorization: {
    url: `${env.CURITY_ISSUER_USER}/oauth/v2/authorize`,
    params: {
      scope: ["openid", "profile"].join(" "),
      /**
       * 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: "acr",
    },
  },
  token: {
    url: `${env.CURITY_ISSUER_USER}/oauth/v2/token`,
  },
  userinfo: {
    url: `${env.CURITY_ISSUER_USER}/oauth/v2/userinfo`,
  },

  profile(profile) {
    return {
      id: profile.id,
      sub: profile.sub,
      given_name: profile.given_name,
    }
  },
} satisfies OIDCConfig<User>

export const config = {
  debug: env.NEXTAUTH_DEBUG,
  providers: [customProvider],
  redirectProxyUrl: env.NEXTAUTH_REDIRECT_PROXY_URL,
  trustHost: true,
  session: {
    strategy: "jwt",
  },
  callbacks: {
    async signIn() {
      return true
    },
    async session({ session, token }) {
      session.error = token.error
      if (session.user) {
        return {
          ...session,
          token,
          user: {
            ...session.user,
            id: token.sub,
          },
        }
      }

      return session
    },
    async redirect({ baseUrl, url }) {
      if (url.startsWith("/")) {
        // Allows relative callback URLs
        return `${baseUrl}${url}`
      } else {
        // Assume absolute URL
        try {
          const parsedUrl = new URL(url)
          if (
            /\.scandichotels\.(dk|de|com|fi|no|se)$/.test(parsedUrl.hostname)
          ) {
            // Allows any subdomains on all top level domains above
            return url
          } else if (parsedUrl.origin === baseUrl) {
            // Allows callback URLs on the same origin
            return url
          }
        } catch (e) {
          console.error(e)
        }
      }
      return baseUrl
    },
    async authorized({ auth, request }) {
      return true
    },
    async jwt({ account, session, token, trigger }) {
      if (account) {
        return {
          access_token: account.access_token,
          expires_at: account.expires_at
            ? account.expires_at * 1000
            : undefined,
          refresh_token: account.refresh_token,
        }
      } else if (Date.now() < token.expires_at) {
        return token
      } else {
        try {
          const response = await fetch(
            `${env.CURITY_ISSUER_USER}/oauth/v2/token`,
            {
              body: new URLSearchParams({
                client_id: env.CURITY_CLIENT_ID_USER,
                client_secret: env.CURITY_CLIENT_SECRET_USER,
                grant_type: "refresh_token",
                refresh_token: token.refresh_token,
              }),
              headers: {
                "Content-Type": "application/x-www-form-urlencoded",
              },
              method: "POST",
            }
          )

          const tokens = await response.json()

          if (!response.ok) {
            throw tokens
          }

          return {
            ...token,
            access_token: tokens.access_token,
            expires_at: tokens.expires_at,
            refresh_token: tokens.refresh_token ?? token.refresh_token,
          }
        } catch (error) {
          return {
            ...token,
            error: "RefreshAccessTokenError" as const,
          }
        }
      }
    },
  },
  // events: {
  //   async signIn() {
  //     console.log("#### SIGNIN EVENT ARGS ######")
  //     console.log(arguments)
  //     console.log("#### END - SIGNIN EVENT ARGS ######")
  //   },
  // async signOut() {
  //   console.log("#### SIGNOUT EVENT ARGS ######")
  //   console.log(arguments)
  //   console.log("#### END - SIGNOUT EVENT ARGS ######")
  // },
  //   async session() {
  //     console.log("#### SESSION EVENT ARGS ######")
  //     console.log(arguments)
  //     console.log("#### END - SESSION EVENT ARGS ######")
  //   },
  // },
  // logger: {
  //   error(code, ...message) {
  //     console.info("ERROR LOGGER")
  //     console.error(code, message)
  //   },
  //   warn(code, ...message) {
  //     console.info("WARN LOGGER")
  //     console.warn(code, message)
  //   },
  //   debug(code, ...message) {
  //     console.info("DEBUG LOGGER")
  //     console.debug(code, message)
  //   },
  // },
} satisfies NextAuthConfig

export const {
  handlers: { GET, POST },
  auth,
  signIn,
  signOut,
} = NextAuth(config)
