import { ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { PermissionsGuard } from '../../domains/identity/guards';
import { isAuditListUnrestricted } from '../../domains/operations/audit/audit-list-scope';
import { PERMISSIONS_KEY } from '../../shared/common/decorators';

/** Mirrors run-seed.ts role permission assignments (SEC010–SEC012). */
const ROLE_PERMISSIONS: Record<string, string[]> = {
  SUPER_ADMIN: ['*'],
  MATCH_ADMIN: [
    'matches.manage',
    'settlement.confirm',
    'content.manage',
    'bets.view',
    'reports.view',
    'audit.view',
  ],
  FINANCE_ADMIN: [
    'wallet.deposit',
    'wallet.withdraw',
    'cashback.confirm',
    'agents.view',
    'agents.credit',
    'users.view',
    'users.create',
    'deposit.manage',
    'deposit.review',
    'reports.view',
    'bets.view',
    'audit.view',
  ],
  SUPPORT: ['users.view', 'users.reset_password', 'bets.view', 'reports.view', 'audit.view'],
};

function mockContext(user: Record<string, unknown>): ExecutionContext {
  return {
    switchToHttp: () => ({
      getRequest: () => ({ user }),
    }),
    getHandler: () => ({}),
    getClass: () => ({}),
  } as ExecutionContext;
}

function guardAllows(user: Record<string, unknown>, ...required: string[]): boolean {
  const reflector = {
    getAllAndOverride: (key: string) => (key === PERMISSIONS_KEY ? required : undefined),
  } as unknown as Reflector;
  const guard = new PermissionsGuard(reflector);
  try {
    return guard.canActivate(mockContext(user));
  } catch {
    return false;
  }
}

function userWithRole(role: string) {
  return {
    userType: 'ADMIN',
    role,
    permissions: ROLE_PERMISSIONS[role] ?? [],
  };
}

describe('Admin RBAC (SEC010–SEC012)', () => {
  it('SEC010: SUPPORT cannot perform wallet deposit', () => {
    const user = userWithRole('SUPPORT');
    expect(guardAllows(user, 'wallet.deposit')).toBe(false);
    expect(guardAllows(user, 'users.view')).toBe(true);
    expect(guardAllows(user, 'users.reset_password')).toBe(true);
  });

  it('SEC011: FINANCE_ADMIN cannot manage matches', () => {
    const user = userWithRole('FINANCE_ADMIN');
    expect(guardAllows(user, 'matches.manage')).toBe(false);
    expect(guardAllows(user, 'wallet.deposit')).toBe(true);
    expect(guardAllows(user, 'agents.credit')).toBe(true);
  });

  it('SEC012: MATCH_ADMIN cannot perform wallet deposit', () => {
    const user = userWithRole('MATCH_ADMIN');
    expect(guardAllows(user, 'wallet.deposit')).toBe(false);
    expect(guardAllows(user, 'settlement.confirm')).toBe(true);
    expect(guardAllows(user, 'content.manage')).toBe(true);
    expect(guardAllows(user, 'settlement.resettle')).toBe(false);
  });

  it('FINANCE_ADMIN has deposit and cashback permissions but not reset database', () => {
    const user = userWithRole('FINANCE_ADMIN');
    expect(guardAllows(user, 'deposit.manage')).toBe(true);
    expect(guardAllows(user, 'deposit.review')).toBe(true);
    expect(guardAllows(user, 'cashback.confirm')).toBe(true);
    expect(guardAllows(user, 'settings.reset_database')).toBe(false);
  });

  it('MATCH_ADMIN cannot manage deposits or confirm cashback', () => {
    const user = userWithRole('MATCH_ADMIN');
    expect(guardAllows(user, 'deposit.manage')).toBe(false);
    expect(guardAllows(user, 'deposit.review')).toBe(false);
    expect(guardAllows(user, 'cashback.confirm')).toBe(false);
  });

  it('SUPPORT cannot confirm cashback or manage deposits', () => {
    const user = userWithRole('SUPPORT');
    expect(guardAllows(user, 'cashback.confirm')).toBe(false);
    expect(guardAllows(user, 'deposit.manage')).toBe(false);
    expect(guardAllows(user, 'deposit.review')).toBe(false);
  });

  it('SUPER_ADMIN bypasses permission checks', () => {
    const user = userWithRole('SUPER_ADMIN');
    expect(guardAllows(user, 'wallet.deposit')).toBe(true);
    expect(guardAllows(user, 'matches.manage')).toBe(true);
    expect(guardAllows(user, 'settings.manage')).toBe(true);
  });

  it('audit list scope: only SUPER_ADMIN is unrestricted', () => {
    expect(isAuditListUnrestricted('SUPER_ADMIN')).toBe(true);
    expect(isAuditListUnrestricted('FINANCE_ADMIN')).toBe(false);
    expect(isAuditListUnrestricted('MATCH_ADMIN')).toBe(false);
  });
});
