import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { AuthService, UserInfo } from '../../shared/services/auth.service';
import { ApiConfigService } from './api-config.service';
import { PermissionAction } from '../models/permission.model';

const SUPER_ADMIN = 'super_admin';

/**
 * Reads the current user's effective permissions (delivered on the UserInfo payload)
 * and answers can(module, action). super_admin always passes. This is a UX mirror —
 * the backend remains the authoritative permission boundary.
 */
@Injectable({ providedIn: 'root' })
export class PermissionService {
    constructor(
        private auth: AuthService,
        private http: HttpClient,
        private apiConfig: ApiConfigService
    ) { }

    /** True if the current user may perform <action> on <module>. */
    can(module: string, action: PermissionAction): boolean {
        const user = this.auth.getCurrentUser();
        if (!user) {
            return false;
        }
        if (user.roles?.includes(SUPER_ADMIN)) {
            return true;
        }
        const moduleActions = user.permissions?.[this.normalizeKey(module)];
        return !!moduleActions && !!moduleActions[action];
    }

    canRead(module: string): boolean    { return this.can(module, 'read'); }
    canWrite(module: string): boolean   { return this.can(module, 'write'); }
    canDelete(module: string): boolean  { return this.can(module, 'delete'); }
    canApprove(module: string): boolean { return this.can(module, 'approve'); }

    /**
     * Re-fetches the current user (with fresh permissions) from GET /api/auth/me.
     * Call after an admin edits the matrix so the UI reflects the change without
     * a re-login. Returns the updated user, or null on failure.
     */
    refresh(): Observable<UserInfo | null> {
        return this.http.get<UserInfo>(`${this.apiConfig.authUrl}/me`).pipe(
            tap(user => this.auth.setCurrentUser(user)),
            map(user => user),
            catchError(() => of(null))
        );
    }

    /**
     * Module names are stored PascalCase in code but arrive as camelCase dictionary
     * keys (server's DictionaryKeyPolicy). Lowercase the first character to match.
     */
    private normalizeKey(module: string): string {
        if (!module) {
            return module;
        }
        return module.charAt(0).toLowerCase() + module.slice(1);
    }
}
