/**
 * Shared auth contracts. Identity implements the authenticator; consumers
 * (users, future modules) receive it by injection from the composition root.
 * No module ever imports another module for auth.
 */
import type { FastifyRequest } from 'fastify';
import { AppError } from './errors.js';

export type Role = 'customer' | 'admin' | 'editor' | 'pos_cashier' | 'pos_manager';

export interface CurrentUser {
  id: string;
  email: string;
  role: Role;
}

/**
 * Resolves the session on the request into the current user.
 * Throws AppError(401) when the request is not authenticated.
 */
export type Authenticate = (request: FastifyRequest) => Promise<CurrentUser>;

/** Throws AppError(403) unless the user holds the required role. */
export function requireRole(user: CurrentUser, role: Role): void {
  if (user.role !== role) {
    throw new AppError(403, 'FORBIDDEN', 'Access denied');
  }
}

/** Throws AppError(403) unless the user holds at least one of the allowed roles.
 *  Use when an endpoint accepts multiple roles (e.g. POS-002 endpoints accept
 *  `pos_cashier`, `pos_manager`, and `admin`). */
export function requireAnyRole(user: CurrentUser, roles: ReadonlyArray<Role>): void {
  if (!roles.includes(user.role)) {
    throw new AppError(403, 'FORBIDDEN', 'Access denied');
  }
}

/** Throws AppError(403) unless the user is the resource owner or an admin. */
export function requireOwnerOrAdmin(user: CurrentUser, ownerId: string): void {
  if (user.role !== 'admin' && user.id !== ownerId) {
    throw new AppError(403, 'FORBIDDEN', 'Access denied');
  }
}
