import { ForbiddenException } from '@nestjs/common';

const SUPER_ADMIN_ROLE = 'super_admin';
const ORGANIZATION_ADMIN_ROLE = 'organization_admin';

type PermissionLike = { key?: string };
type MeLikeUser = {
  roles?: { key?: string }[];
  permissions?: PermissionLike[];
  employee?:
    | { position?: { permissions?: PermissionLike[] }; delegatedPositions?: { permissions?: PermissionLike[] }[] }
    | { positions?: { permissions?: PermissionLike[] }[] }[]
    | null;
};

export function isSuperAdmin(user: MeLikeUser | null | undefined): boolean {
  return user?.roles?.some((r) => r.key === SUPER_ADMIN_ROLE) ?? false;
}

export function isOrganizationAdmin(user: MeLikeUser | null | undefined): boolean {
  return user?.roles?.some((r) => r.key === ORGANIZATION_ADMIN_ROLE) ?? false;
}

export function collectPermissionKeys(user: MeLikeUser | null | undefined): string[] {
  if (!user) return [];

  const keys = new Set<string>();

  for (const p of user.permissions ?? []) {
    if (p.key) keys.add(p.key);
  }

  const employee = user.employee;
  if (!employee) return [...keys];

  if (Array.isArray(employee)) {
    for (const emp of employee) {
      for (const pos of emp.positions ?? []) {
        for (const p of pos.permissions ?? []) {
          if (p.key) keys.add(p.key);
        }
      }
    }
    return [...keys];
  }

  for (const p of employee.position?.permissions ?? []) {
    if (p.key) keys.add(p.key);
  }
  for (const delegated of employee.delegatedPositions ?? []) {
    for (const p of delegated.permissions ?? []) {
      if (p.key) keys.add(p.key);
    }
  }

  return [...keys];
}

export function hasPassengerPermission(
  user: MeLikeUser | null | undefined,
  permissionKey: string,
): boolean {
  if (!user) return false;
  if (isSuperAdmin(user) || isOrganizationAdmin(user)) return true;
  return collectPermissionKeys(user).includes(permissionKey);
}

export function assertPassengerPermission(
  user: MeLikeUser | null | undefined,
  permissionKey: string,
): void {
  if (hasPassengerPermission(user, permissionKey)) return;
  throw new ForbiddenException(`Missing permission: ${permissionKey}`);
}
