import { FastifyPluginAsync, FastifyRequest } from "fastify";
import fastifyPlugin from "fastify-plugin";
import fastifyJwt from "@fastify/jwt";
import fastifyCookie from "@fastify/cookie";
import fastifyOauth2 from "@fastify/oauth2";

declare module "fastify" {
  interface FastifyInstance {
    authenticate: (request: FastifyRequest) => Promise<void>;
    oauth2Discord: any;
  }
}

declare module "@fastify/jwt" {
  interface FastifyJWT {
    user: {
      id: string;
      username: string;
      email?: string;
      avatar?: string;
      isAdmin: boolean;
    };
  }
}

const getJwtSecret = (): string => {
  const secret = process.env.JWT_SECRET;
  if (!secret) {
    throw new Error("JWT_SECRET environment variable is required");
  }
  return secret;
};

const authPlugin: FastifyPluginAsync = async (app) => {
  const jwtSecret = getJwtSecret();

  // Register cookie plugin with signing secret
  app.register(fastifyCookie, {
    secret: jwtSecret,
  });

  // Register JWT plugin
  app.register(fastifyJwt, {
    secret: jwtSecret,
    sign: {
      algorithm: "HS256",
    },
    verify: {
      algorithms: ["HS256"],
    },
    cookie: {
      cookieName: "auth-token",
      signed: true,
    },
    formatUser: (payload: { sub: string; email?: string; username: string; isAdmin: boolean }) => {
      return {
        id: payload.sub,
        email: payload.email,
        username: payload.username,
        isAdmin: payload.isAdmin,
      };
    },
  });

  // Register Discord OAuth2
  app.register(fastifyOauth2, {
    name: "oauth2Discord",
    scope: ["identify", "email", "guilds", "guilds.members.read"],
    credentials: {
      client: {
        id: process.env.DISCORD_CLIENT_ID || "",
        secret: process.env.DISCORD_CLIENT_SECRET || "",
      },
      auth: fastifyOauth2.DISCORD_CONFIGURATION,
    },
    startRedirectPath: "/api/auth/login",
    callbackUri: `${process.env.BASE_URL || "http://localhost:3000"}/api/auth/callback`,
  });

  // Authentication decorator
  app.decorate("authenticate", async (request: FastifyRequest) => {
    try {
      await request.jwtVerify();
    } catch (err) {
      const error = new Error("Invalid token");
      (error as any).statusCode = 401;
      throw error;
    }
  });
};

export default fastifyPlugin(authPlugin);