import { Injectable } from '@angular/core'

import { Observable, of } from 'rxjs'
import { map } from 'rxjs/operators'

import { RoleReadNoUsers, ApiService, Token, UserRead } from '../openapi'
import { BootstrapService } from './bootstrap.service'
import { ConfigService } from './config.service'

@Injectable()
export class AuthenticationService {
    roles: RoleReadNoUsers[] = []

    constructor(
        public api: ApiService,
        public bootstrapService: BootstrapService,
        public configService: ConfigService,
    ) {
        // set token if saved in local storage
        // this.user.next(<User>JSON.parse(localStorage.getItem('user')))
    }

    isLoggedIn() : Observable<boolean> {
        return this.configService.conf.pipe(map(
            conf => !!conf.bsData?.user
        ))

        // if (!this.user.value) {
        //     return from([false])
        // }
        // let body = JSON.stringify({
        //     token: this.user.value.token,
        // })
        // return this._http.post(
        //     '/auth/isLoggedIn',
        //     body,
        //     {
        //         headers: new HttpHeaders({ 'Content-Type': 'application/json' })
        //     }
        // ).pipe(
        //     map(resp => true),
        //     catchError(
        //         err => {
        //             const userName = this.user.value['userName']
        //             this.user.next(undefined)
        //             this.roles = []
        //             localStorage.removeItem('user')
        //             return throwError(
        //                 () => new Error('Session of user "' + userName + '" expired.')
        //             )
        //         }
        //     )
        // )
    }

    login(username: string, password: string): Observable<Token> {
        // const headers = new HttpHeaders({'Content-Type': 'application/x-www-form-urlencoded'})
        // var formData: any = new URLSearchParams()
        // formData.set('username', userName)
        // formData.set('password', password)
        return this.api.loginForAccessTokenApiTokenPost({
            "formData": {
                username: username,
                password: password
            }
        }).pipe(map(
            token => {
                localStorage.setItem('token', token.access_token)
                this.bootstrapService.get().subscribe(
                    bsData => this.configService.setConf(bsData)
                )
                return token
            }
        ))
    }

    logout() {
        // XXX: not completly safe: the server might be down:
        //      We should actually *check* that the logout response is OK and display message
        // clear token remove user from local storage to log user out
        // let has_token: boolean = this.user.value && !!this.user.value.token
        // const has_token: boolean = !!localStorage.getItem('token')
        // localStorage.removeItem('user')
        // this.user.next(undefined)
        // this.roles = []

        // Tell server that the user has logged out
        this.api.logoutApiLogoutGet().subscribe({
            next: res => {
                localStorage.removeItem('token')
                this.bootstrapService.get().subscribe(
                    bsData => this.configService.setConf(bsData)
                )
            },
            error: error => {
                localStorage.removeItem('token')
            }
        })
    }

    logoutAdmin(): void {
    }

    getUser(): Observable<UserRead> {
        return this.configService.conf.pipe(map(
            conf => conf.bsData?.user
        ))
    }

    isAuthorized(roles: string[]): Observable<boolean> {
        // Return true if at least one role in given list matches one role of the authenticated user
        if (roles.length == 0) return of(true)
        if (roles.every(role => role == undefined)) return of(true)
        return this.configService.conf.pipe(map(
            conf => conf.bsData?.user?.roles?.filter(value => -1 !== roles.indexOf(value.name)).length > 0
        ))
    }

    isNotAuthorized(roles: string[]): Observable<boolean> {
        return this.isAuthorized(roles).pipe(map(
            isAuthorized => !isAuthorized
        ))
    }
}
