import type { FastifyRequest, FastifyReply } from 'fastify';
import { ForbiddenError } from '../utils/errors.js';
import { emitter } from '../events/emitter.js';
import { logger } from '../utils/logger.js';

export function authorize(requiredPermission: string) {
  return async (request: FastifyRequest, _reply: FastifyReply) => {
    const user = request.user;
    if (!user) throw new ForbiddenError('Authentication required');

    const perms = user.permissions ?? [];
    if (perms.includes('*')) return;
    if (perms.includes(requiredPermission)) return;

    logger.warn(
      { userId: user.id, requiredPermission, url: request.url, ip: request.ip },
      'Permission denied',
    );
    emitter.emit('activity.create', {
      user_id: user.id,
      entity_type: 'auth',
      action: 'permission_denied',
      description: `Denied "${requiredPermission}" on ${request.url}`,
      ip_address: request.ip,
    });

    throw new ForbiddenError('Insufficient permissions');
  };
}

// Passes if the user holds ANY one of the given permissions — used for
// browse/list endpoints that legitimately serve more than one page (e.g.
// GET /api/clients is needed both by the Clients page under CLIENTS_VIEW
// and by the Order create/edit form under ORDERS_CREATE/ORDERS_EDIT, since
// picking a client to attach to an order requires browsing the client list).
export function authorizeAny(requiredPermissions: string[]) {
  return async (request: FastifyRequest, _reply: FastifyReply) => {
    const user = request.user;
    if (!user) throw new ForbiddenError('Authentication required');

    const perms = user.permissions ?? [];
    if (perms.includes('*')) return;
    if (requiredPermissions.some((p) => perms.includes(p))) return;

    logger.warn(
      { userId: user.id, requiredPermissions, url: request.url, ip: request.ip },
      'Permission denied',
    );
    emitter.emit('activity.create', {
      user_id: user.id,
      entity_type: 'auth',
      action: 'permission_denied',
      description: `Denied "${requiredPermissions.join(' or ')}" on ${request.url}`,
      ip_address: request.ip,
    });

    throw new ForbiddenError('Insufficient permissions');
  };
}
