// Copyright IBM Corp. 2019. All Rights Reserved.
// Node module: @loopback/authentication
// This file is licensed under the MIT License.
// License text available at https://opensource.org/licenses/MIT

import { inject } from '@loopback/context'
import { HttpErrors, Request } from '@loopback/rest'
import { AuthenticationStrategy, TokenService } from '@loopback/authentication'
import { UserProfile } from '@loopback/security'
import { TokenServiceBindings } from '../keys'

export class JWTAuthenticationStrategy implements AuthenticationStrategy {
  name = 'jwt'

  constructor(
    @inject(TokenServiceBindings.TOKEN_SERVICE)
    public tokenService: TokenService
  ) {}

  async authenticate(request: Request): Promise<UserProfile | undefined> {
    const token: string = this.extractCredentials(request)
    const userProfile: UserProfile = await this.tokenService.verifyToken(token)
    return userProfile
  }

  extractCredentials(request: Request): string {
    if (!request.headers.authorization) {
      throw new HttpErrors.Unauthorized(`Authorization header not found.`)
    }

    const authHeaderValue = request.headers.authorization
    if (!authHeaderValue.startsWith('Bearer')) {
      throw new HttpErrors.Unauthorized(
        `Authorization header is not of type 'Bearer'.`
      )
    }

    const parts = authHeaderValue.split(' ')
    if (parts.length !== 2)
      throw new HttpErrors.Unauthorized(
        `Authorization header value has too many parts. It must follow the pattern: 'Bearer xx.yy.zz' where xx.yy.zz is a valid JWT token.`
      )
    const token = parts[1]

    return token
  }
}
