import { Injectable, inject } from '@angular/core'
import { Router } from '@angular/router'
import { SessionInfo } from '@core/types'
import { WSService } from '@frontend/ws'
import { DefaultService, UserResponse } from '@api-client/angular'
import { jwtDecode } from 'jwt-decode'
import { BehaviorSubject, Observable } from 'rxjs'
import { map, tap } from 'rxjs/operators'

const USER_STORAGE_KEY = '939ccaf1e62d5ead1c6251e8'

@Injectable({
	providedIn: 'root',
})
export class AuthService {
	private readonly _router = inject(Router)
	private readonly _wsService = inject(WSService)
	private readonly _apiService = inject(DefaultService)

	private readonly sessionInfoSubject = new BehaviorSubject<SessionInfo | undefined>(undefined)
	readonly sessionInfo$ = this.sessionInfoSubject.asObservable()

	private readonly userDataSubject = new BehaviorSubject<UserResponse | undefined>(undefined)
	readonly userData$ = this.userDataSubject.asObservable()

	constructor() {
		const token = window.localStorage.getItem(USER_STORAGE_KEY)
		if (token) {
			this.sessionInfoSubject.next(this.extractToken(token))
		}
	}

	get userData(): UserResponse {
		return this.userDataSubject.getValue() as UserResponse
	}

	get sessionInfo(): SessionInfo | undefined {
		return this.sessionInfoSubject.getValue()
	}

	get token(): string | undefined {
		return window.localStorage.getItem(USER_STORAGE_KEY) ?? undefined
	}

	get tenantId(): string | undefined {
		return this.sessionInfo?.tenantId
	}

	isLoggedIn(): boolean {
		return !!this.sessionInfo
	}

	login(email: string, password: string): Observable<SessionInfo> {
		return this._apiService.authControllerLogin({ email, password }).pipe(
			map(({ access_token }) => {
				window.localStorage.setItem(USER_STORAGE_KEY, access_token)

				const user = this.extractToken(access_token)
				this.sessionInfoSubject.next(user)

				this._wsService.connect(this.tenantId!, user.id)

				return user
			}),
		)
	}

	logout() {
		window.localStorage.removeItem(USER_STORAGE_KEY)
		this.sessionInfoSubject.next(undefined)
		this._router.navigate(['/auth/login'])
	}

	updatePassword(currentPassword: string, newPassword: string): Observable<void> {
		return this._apiService.authControllerUpdatePassword({ currentPassword, newPassword })
	}

	loadUser(): Observable<UserResponse> {
		return this._apiService.userControllerGetProfile().pipe(
			tap((user) => {
				this.userDataSubject.next(user)
				this._wsService.connect(this.tenantId!, user.id)
			}),
		)
	}

	private extractToken(token: string): SessionInfo {
		return jwtDecode(token)
	}
}
