import { Jwt } from '../auth/types'
import { AuthService } from '../auth'
import { RefreshableJwt } from '..'
import { ICredential, CredentialType } from './credential'
import { extractOrganizersFromJwt } from '../utils/jwt'

/**
 * This class is used for restoring the authorization
 */
export class JwtCredentials implements ICredential {
	readonly type: CredentialType.Jwt

	constructor(private jwt: Jwt | RefreshableJwt) {}

	getToken(): Jwt | RefreshableJwt {
		return this.jwt
	}

	async authorize(
		authService: AuthService,
		organizer?: string
	): Promise<Jwt | RefreshableJwt> {
		if (
			isRefreshableToken(this.jwt) &&
			organizer &&
			organizer !== this.jwt.organizerId &&
			!this.hasOrganizerInToken(this.jwt, organizer)
		) {
			// Refresh an organizer if it is specified and theres been a change
			// This is since we need a new jwt for the new organizer
			this.jwt.organizerId = organizer
			this.jwt = await authService.refreshToken(this.jwt)
		}
		return this.jwt
	}

	async refreshToken(
		authService: AuthService,
		organizer?: string
	): Promise<Jwt | RefreshableJwt> {
		// If the token can be refreshed, do it
		if (isRefreshableToken(this.jwt)) {
			if (organizer) {
				this.jwt.organizerId = organizer
			}
			this.jwt = await authService.refreshToken(this.jwt)
		}
		return this.jwt
	}

	private hasOrganizerInToken(jwt: Jwt, organizer: string) {
		if (!jwt?.token || !organizer) return false
		
		const orgsInToken = extractOrganizersFromJwt(jwt)
		return !!orgsInToken.find((org) => org == organizer)
	}
}

function isRefreshableToken(jwt: Jwt | RefreshableJwt): jwt is RefreshableJwt {
	return (<RefreshableJwt>jwt).refreshToken !== undefined
}
