import { Injectable, inject } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { BehaviorSubject, firstValueFrom, map, Observable, tap } from 'rxjs'; import { getAppConfig } from './app-config.service'; import { AppUser, AuthTokenResponse } from '../interfaces/auth'; const TOKEN_KEY = 'kmtn_access_token'; @Injectable({ providedIn: 'root', }) export class AuthService { private http = inject(HttpClient); private baseUrl = `${getAppConfig().apiBaseUrl}/api/auth`; private authStateSubject = new BehaviorSubject(null); /** Observable that emits the current auth state. */ readonly authState$: Observable = this.authStateSubject.asObservable(); constructor() { // Check for existing token on init this._initAuth(); } /** Login with username/password (bootstrap admin). */ login(username: string, password: string): Observable { return this.http.post(`${this.baseUrl}/login`, { username, password, }).pipe( tap((resp) => localStorage.setItem(TOKEN_KEY, resp.access_token)), ); } /** Login with Google ID token. */ loginWithGoogle(idToken: string): Observable { return this.http.post(`${this.baseUrl}/google`, { id_token: idToken, }).pipe( tap((resp) => localStorage.setItem(TOKEN_KEY, resp.access_token)), ); } /** Clear stored token and reset auth state. */ logout(): void { localStorage.removeItem(TOKEN_KEY); this.authStateSubject.next(null); } /** Fetch current user info from the API. */ getCurrentUser(): Promise { const token = this._getToken(); if (!token) return Promise.resolve(null); return firstValueFrom( this.http.get(`${this.baseUrl}/me`).pipe( tap((user) => this.authStateSubject.next(user)), map((user) => user), ) ).catch(() => { this.logout(); return null; }); } /** Check if there is a stored token. */ isLoggedIn(): boolean { return !!this._getToken(); } /** Check if the current user is an admin (synchronous, based on cached state). */ isAdmin(): boolean { return this.authStateSubject.value?.is_admin ?? false; } /** Get the current user synchronously (from cached state). */ getUser(): AppUser | null { return this.authStateSubject.value; } // ── Private ────────────────────────────────────────────── private _getToken(): string | null { return localStorage.getItem(TOKEN_KEY); } private async _initAuth(): Promise { const token = this._getToken(); if (token) { await this.getCurrentUser(); } } }