import type * as Hapi from "@hapi/hapi";
import { IAppConfig } from "@digiresilience/metamigo-config";
import { postgraphile, HttpRequestHandler } from "postgraphile";
import { getPostGraphileOptions } from "@digiresilience/metamigo-db";

export interface HapiPostgraphileOptions {}

const PostgraphilePlugin: Hapi.Plugin<HapiPostgraphileOptions> = {
  name: "postgraphilePlugin",
  version: "1.0.0",
  register: async function (server, options: HapiPostgraphileOptions) {
    const config = server.config();
    const postgraphileMiddleware: HttpRequestHandler = postgraphile(
      config.postgraphile.authConnection,
      "app_public",
      {
        ...getPostGraphileOptions(),
        jwtSecret: "",
        pgSettings: async (req) => {
          const auth = (req as any).hapiAuth;
          if (auth.isAuthenticated && auth.credentials.user.userRole) {
            return {
              role: `app_${auth.credentials.user.userRole}`,
              "jwt.claims.session_id": auth.credentials.sessionToken,
            };
          } else {
            return {
              role: "app_anonymous",
            };
          }
        },
      }
    );

    server.route({
      method: ["POST"],
      path: "/graphql",
      options: {
        auth: "session-id-bearer-token",
        payload: {
          parse: false, // this disables payload parsing
          output: "stream", // ensures the payload is a readable stream which postgraphile expects
        },
      },
      handler: (request: Hapi.Request, h: Hapi.ResponseToolkit) => {
        return new Promise((resolve, reject) => {
          const rawReq = request.raw.req as any;
          rawReq.hapiAuth = request.auth;
          postgraphileMiddleware(rawReq, request.raw.res, (error) => {
            if (error) {
              reject(error);
            } else {
              // PostGraphile responds directly to the request
              resolve(h.abandon);
            }
          });
        });
      },
    });
  },
};

export const registerPostgraphile = async (
  server: Hapi.Server,
  config: IAppConfig
): Promise<void> => {
  await server.register({
    plugin: PostgraphilePlugin,
    options: {},
  });
};
