import NextAuth from 'next-auth'
import KeycloakProvider from 'next-auth/providers/keycloak'

const secretSessionKey = process.env.SECRET_SESSION_KEY || 'UItTuD1HcGXIj8ZfHUswhYdNd40Lc325R8VlxQPUoR0='
const clientId = process.env.KEY_CLOAK_CLIENT_ID || 'gwdg-fdoman-test'
const clientSecret = process.env.KEY_CLOAK_CLIENT_SECRET || ''
const issuer = process.env.KEY_CLOAK_ISSUER || 'https://keycloak.sso.gwdg.de/auth/realms/academiccloud'

async function refreshAccessToken (token: any) {
  try {
    const url = issuer + '/protocol/openid-connect/token'
    const params = new URLSearchParams({
      client_id: clientId,
      client_secret: clientSecret,
      grant_type: 'refresh_token',
      refresh_token: token.refreshToken
    }).toString()

    const response = await fetch(url, {
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      },
      method: 'POST',
      body: params
    })

    const refreshedTokens = await response.json()

    if (!response.ok) {
      throw refreshedTokens
    }
    console.log('### refreshToken', new Date().toISOString(), refreshedTokens, '### ### ###')

    return {
      ...token,
      accessToken: refreshedTokens.access_token,
      accessTokenExpires: Date.now() + refreshedTokens.expires_in * 1000,
      refreshToken: refreshedTokens.refresh_token ?? token.refreshToken // Fall back to old refresh token
    }
  } catch (error) {
    console.log('### RefreshAccessTokenError', error, '### ### ###')

    return {
      ...token,
      error: 'RefreshAccessTokenError'
    }
  }
}

export const authOptions = {
  // adapter: UnstorageAdapter(storage),
  session: {
    maxAge: 172800 // 48h
  },
  debug: true,
  // Configure one or more authentication providers
  providers: [
    // !!! Should be stored in .env file.
    KeycloakProvider({
      clientId,
      clientSecret,
      issuer,
      // authorization: { params: { scope: 'openid profile email' } },
      profile (profile) {
        console.log('### profile', profile, '### ### ###')
        return {
          id: profile.sub,
          name: profile.name ?? profile.preferred_username
        }
      }
    })
  ],
  callbacks: {
    async signIn ({ user, account, profile, email, credentials }: any) {
      console.log('### signIn', user, account, profile, email, credentials, '### ### ###')
      return true
    },
    async session ({ session, user, token }: any) {
      console.log('### session', session, user, token, '### ### ###')

      session.user = token.user
      session.accessToken = token.accessToken
      session.error = token.error

      return session
    },
    async redirect ({ url, baseUrl }: any) {
      console.log('### redirect', url, baseUrl, '### ### ###')
      return Promise.resolve(url)
    },
    async jwt ({ token, user, account, profile, isNewUser }: any) {
      console.log('### jwt', token, user, account, profile, isNewUser, '### ### ###')

      // Initial sign in
      if (account && user) {
        return {
          lastRefresh: Date.now(),
          accessToken: account.access_token,
          accessTokenExpires: account.expires_at,
          refreshToken: account.refresh_token,
          user
        }
      }

      if (token.lastRefresh + 60000 > Date.now()) {
        // return if last refresh is 10 seconds or younger
        return token
      }

      // Access token has expired, try to update it
      return refreshAccessToken(token)
    }
  },
  secret: secretSessionKey
}
export default NextAuth(authOptions)