import { FastifyRequest, FastifyReply } from 'fastify';
import jwt from 'jsonwebtoken';
import { UserRoleType } from '../constants/roles';
import { User } from '../apps/_app/entities/user/_User';
import { EntityManager } from '@mikro-orm/core';

interface UserPayload extends jwt.JwtPayload {
  id: number;
  roles: UserRoleType;
}

const auth = (requiredRoles: UserRoleType[]) => async (request: FastifyRequest, reply: FastifyReply) => {
  try {
    const token = request.headers.authorization?.split(' ')[1];

    if (!token) {
      return reply.code(401).send({ error: 'Authentication failed: No token provided' });
    }

    const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as UserPayload;

    const hasRequiredRole = requiredRoles.some((role) => decoded.roles && decoded.roles.includes(role));

    if (!hasRequiredRole) {
      return reply.code(403).send({ error: 'Unauthorized: Insufficient role' });
    }

    // Fetch the full user object from the database
    const em = request.server.orm.em as EntityManager;
    const user = await em.findOne(User, { id: decoded.id });

    if (!user) {
      return reply.code(401).send({ error: 'User not found' });
    }

    request.user = user;
  } catch (error) {
    const typedError = error as Error;
    return reply.code(401).send({ error: 'Authentication failed', info: typedError.message });
  }
};

export default auth;
