import { WithScopeAccess } from '@interfaces/entities/Access';
import { USER_SCOPES } from '@/constants/entities/Scope';
import { User } from 'oidc-client';

/*
 * Абстракция для разграничения доступа по скоупам
 */
export class AccessController {
  private userScopes: USER_SCOPES[];
  scopes: typeof USER_SCOPES;
  constructor(user: Partial<User>) {
    this.init(user);
    this.scopes = USER_SCOPES;
  }

  init({ scope = '' }: Partial<User>): void {
    this.userScopes = scope.split(' ') as USER_SCOPES[];
  }

  // Просеиваем те элементы, доступ до которых есть у скоупа пользователя
  scopesSift<T>(payload: WithScopeAccess<T>[] = []): T[] {
    return this.scopesSiftWithoutDataMapping(payload)
      .map(({ data }) => data);
  }

  scopesSiftWithoutDataMapping<T>(payload: WithScopeAccess<T>[] = []): WithScopeAccess<T>[] {
    return payload
      .filter(({ access }) => {
        const { openedTo = [] } = access ?? {};
        if (openedTo.length) {
          return openedTo.some((scope) => this.userScopes.includes(scope));
        }
        return true;
      });
  }

  // Проверка на наличие скоупа у пользователя
  haveScope(scope: USER_SCOPES): boolean {
    return this.userScopes.includes(scope);
  }

  // Проверка на полное пересечение скоупов
  haveScopes(scopes: USER_SCOPES[] = []): boolean {
        return scopes.every((scope) => this.userScopes.includes(scope));
  }

  // Пересечение хотя бы по 1 из списка скоупов
  haveOneOfScope(scopes: USER_SCOPES[] = []): boolean {
    return this.userScopes.some((scope) => scopes.includes(scope));
  }

  // Проверка видимости кнопок
  haveVisible(scopes:USER_SCOPES[] = [], mode:any, scopesMode:any): boolean {
    return mode === scopesMode
            ? this.haveScopes(scopes)
            : this.haveOneOfScope(scopes)
  }
}
