/**
 * Row-level visibility policy for the Queries + Bookings list pages.
 *
 * Single-control model (client decision 2026-10-10):
 *
 *   - A role sees ALL rows in the tenant (every hierarchy) ONLY when its
 *     **View All Bookings/Queries** flag (`view_all_bookings_queries`) is
 *     on AND it has view-or-higher on that module. Currently intended for
 *     Admin + Accountant.
 *   - EVERYONE else — regardless of their Booking permission level — sees
 *     only their OWN rows plus their reporting chain (`parent_user_id`
 *     tree). So two Sales Heads never see each other's data, even if both
 *     have Booking = All/Delete.
 *
 *   The Booking permission level (view / create / edit / delete) governs
 *   ONLY what actions a user may perform (via PermissionGuard +
 *   @Permissions) — it does NOT affect data visibility. The old
 *   "Booking: Delete ⇒ see everything" shortcut was removed on 2026-10-10
 *   so the View-All flag is the sole control.
 *
 *   "Own" = rows owned by the viewer OR anyone in their reporting chain:
 *           `created_by` / `sales_team[]` match the viewer or any
 *           direct/indirect report.
 *
 * The flag never grants module access or bypasses PermissionGuard — it
 * only widens row visibility for a module the user can already view.
 */
import { type ClsService } from 'nestjs-cls';
import { CLS_ROLE_VIEW_ALL_BOOKINGS_QUERIES, CLS_USER_PERMISSIONS } from '../cls/cls.constants';

export type VisibilityScope = 'all' | 'own';

export type RowVisibilityModule = 'query' | 'booking';

function hasModuleViewPermission(
  permissions: Record<string, string> | null | undefined,
  module: RowVisibilityModule,
): boolean {
  if (!permissions) return false;
  const level = permissions[module];
  return !!level && level !== 'none';
}

/**
 * Per-module row visibility. Returns 'all' ONLY when the View-All flag is
 * set AND the user can view the module; otherwise 'own' (self + reporting
 * chain). No permission level — including Booking = Delete — grants
 * cross-hierarchy visibility on its own.
 */
export function getModuleVisibilityScope(
  permissions: Record<string, string> | null | undefined,
  module: RowVisibilityModule,
  viewAllBookingsQueries: boolean,
): VisibilityScope {
  if (viewAllBookingsQueries && hasModuleViewPermission(permissions, module)) {
    return 'all';
  }
  return 'own';
}

/**
 * Convenience wrapper — read permissions + the View-All flag from CLS and
 * resolve scope in one call. Use inside services / repos that already have
 * ClsService. Falls back to 'own' if CLS isn't populated (e.g. CLI / cron),
 * the safe direction: never over-share when the policy can't be evaluated.
 */
export function getModuleVisibilityScopeFromCls(
  cls: ClsService,
  module: RowVisibilityModule,
): VisibilityScope {
  const permissions = cls.get<Record<string, string> | null>(CLS_USER_PERMISSIONS);
  const viewAll = cls.get<boolean>(CLS_ROLE_VIEW_ALL_BOOKINGS_QUERIES) === true;
  return getModuleVisibilityScope(permissions, module, viewAll);
}
