import jwt from 'jsonwebtoken' //eslint-disable-line

type AccessTokenResponse = {
  access_token: string,
  token_type: string,
  expires_in: number,
  refresh_token: string,
  scope: string
}

type DiscordUser = {
  id: string,
  username: string,
  discriminator: string,
  avatar: string,
  bot?: boolean,
  system?: boolean,
  mfa_enabled?: boolean,
  banner?: string,
  accent_color?: number,
  locale?: string,
  verified?: boolean,
  email?: string,
  flags?: number,
  premium_type?: number,
  public_flags?: number
}

export default defineEventHandler(async (event) => {
  const { code }: { code?: string } = getQuery(event)

  if (!code) {
    return sendRedirect(event, '/', 302)
  }

  let tokenResponse: AccessTokenResponse
  let authorizationResponse: DiscordUser
  try {
    tokenResponse = await $fetch('https://discord.com/api/oauth2/token', {
      method: 'POST',
      body: new URLSearchParams({
        client_id: config.discordClientId,
        client_secret: config.discordClientSecret,
        code,
        grant_type: 'authorization_code',
        redirect_uri: config.oauthRedirectUri,
        scope: 'identify'
      }),
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded'
      }
    })

    authorizationResponse = await $fetch('https://discord.com/api/users/@me', {
      headers: {
        authorization: `Bearer ${tokenResponse.access_token}`
      }
    })
  } catch (e) {
    console.error('Discord authentication failed', e)

    throw createError({ statusCode: 500, statusMessage: 'Discord authentication failed' })
  }

  try {
    const user = await UserModel.findOneAndUpdate({ 'discord.id': authorizationResponse.id }, {
      $set: {
        discord: {
          id: authorizationResponse.id,
          username: authorizationResponse.username,
          avatarHash: authorizationResponse.avatar
        }
      },
      $setOnInsert: {
        username: authorizationResponse.username
      }
    }, { upsert: true, returnDocument: 'after' })

    const token = jwt.sign({
      accessToken: tokenResponse.access_token,
      refreshToken: tokenResponse.refresh_token,
      discordId: authorizationResponse.id,
      userId: user._id
    }, config.jwtSecret, { expiresIn: tokenResponse.expires_in })

    setCookie(event, 'jwt', token, { httpOnly: true, maxAge: tokenResponse.expires_in * 1000 })
  } catch (e) {
    console.error('Updating user information failed', e)

    throw createError({ statusCode: 500, statusMessage: 'Updating user information failed' })
  }

  return sendRedirect(event, '/', 302)
})
