/**
 * ╔═══════════════════════════════════════════════════════════════╗
 * ║  RoleGuard — RBAC-защита маршрутов                            ║
 * ╚═══════════════════════════════════════════════════════════════╝
 *
 * Уровни доступа (совпадают с infud-server-v4.js):
 *   readonly   = 1  (просмотр Производство, Склад)
 *   tech       = 2  (+ ввод персонала, остановки)
 *   dispatcher = 3  (+ все разделы, отчёты)
 *   engineer   = 4  (+ подключения, диагностика)
 *   admin      = 5  (полный доступ)
 *
 * Применение:
 *   @UseGuards(JwtAuthGuard, RoleGuard)
 *   @MinLevel(4)                           // числовой уровень
 *   // или
 *   @Roles('admin', 'engineer')            // по именам ролей
 */

import {
  Injectable, CanActivate, ExecutionContext,
  ForbiddenException, SetMetadata,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';

// ── Числовые уровни доступа ──────────────────────────────────────
export type UserRole = 'readonly' | 'tech' | 'dispatcher' | 'engineer' | 'admin';

export const ROLE_LEVELS: Record<UserRole, number> = {
  readonly:   1,
  tech:       2,
  dispatcher: 3,
  engineer:   4,
  admin:      5,
};

// ── Декораторы ───────────────────────────────────────────────────
export const ROLES_KEY     = 'required_roles';
export const MIN_LEVEL_KEY = 'min_level';

/** @Roles('admin', 'engineer') — проверка по именам */
export const Roles     = (...roles: UserRole[]) => SetMetadata(ROLES_KEY, roles);
/** @MinLevel(4) — проверка по числовому уровню */
export const MinLevel  = (level: number)        => SetMetadata(MIN_LEVEL_KEY, level);

// ── Guard ─────────────────────────────────────────────────────────
@Injectable()
export class RoleGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {}

  canActivate(ctx: ExecutionContext): boolean {
    const request = ctx.switchToHttp().getRequest();
    const user    = request.user;

    // Если JWT не верифицирован — JwtAuthGuard уже бросил ошибку раньше
    if (!user) throw new ForbiddenException('Нет авторизации');

    const userLevel = ROLE_LEVELS[user.role as UserRole] ?? 0;

    // Проверка по минимальному уровню (@MinLevel)
    const minLevel = this.reflector.getAllAndOverride<number>(MIN_LEVEL_KEY, [
      ctx.getHandler(), ctx.getClass(),
    ]);
    if (minLevel != null && userLevel < minLevel) {
      throw new ForbiddenException(
        `Требуется уровень доступа ≥ ${minLevel}, у вас: ${userLevel} (${user.role})`
      );
    }

    // Проверка по именам ролей (@Roles)
    const requiredRoles = this.reflector.getAllAndOverride<UserRole[]>(ROLES_KEY, [
      ctx.getHandler(), ctx.getClass(),
    ]);
    if (requiredRoles?.length) {
      const minRequired = Math.min(...requiredRoles.map(r => ROLE_LEVELS[r] ?? 99));
      if (userLevel < minRequired) {
        throw new ForbiddenException(
          `Требуется роль: ${requiredRoles.join(' / ')}`
        );
      }
    }

    return true;
  }
}
