import fastifyJwt from "@fastify/jwt";
import type { FastifyInstance, FastifyReply, FastifyRequest } from "fastify";
import fp from "fastify-plugin";
import { env } from "../config/env.js";
import type { Role } from "./users.js";

/**
 * Autenticação do painel: JWT de sessão + guardas de papel.
 *
 * Controle de acesso (CLAUDE.md): `admin` vê/edita config sensível (chaves,
 * proxy); `operator` opera o dia a dia. As rotas do cofre de chaves exigem
 * `admin`.
 */

export interface SessionUser {
  sub: number;
  email: string;
  role: Role;
}

// Augmenta os tipos do Fastify/JWT com o nosso payload e decorators.
declare module "@fastify/jwt" {
  interface FastifyJWT {
    payload: SessionUser;
    user: SessionUser;
  }
}
declare module "fastify" {
  interface FastifyInstance {
    /** Pré-handler: exige um JWT válido. Popula `request.user`. */
    authenticate: (req: FastifyRequest, reply: FastifyReply) => Promise<void>;
    /** Fábrica de pré-handler que exige um papel específico. */
    requireRole: (
      role: Role,
    ) => (req: FastifyRequest, reply: FastifyReply) => Promise<void>;
  }
}

async function authPluginImpl(app: FastifyInstance): Promise<void> {
  await app.register(fastifyJwt, {
    secret: env.JWT_SECRET,
    sign: { expiresIn: env.JWT_EXPIRES_IN },
  });

  app.decorate(
    "authenticate",
    async (req: FastifyRequest, reply: FastifyReply): Promise<void> => {
      try {
        await req.jwtVerify();
      } catch {
        await reply.code(401).send({ error: "Não autenticado." });
      }
    },
  );

  app.decorate("requireRole", (role: Role) => {
    return async (req: FastifyRequest, reply: FastifyReply): Promise<void> => {
      try {
        await req.jwtVerify();
      } catch {
        await reply.code(401).send({ error: "Não autenticado." });
        return;
      }
      if (req.user.role !== role) {
        await reply.code(403).send({ error: "Acesso negado." });
      }
    };
  });
}

export const authPlugin = fp(authPluginImpl, { name: "auth" });
