import * as Hapi from "@hapi/hapi";
import * as Hoek from "@hapi/hoek";
import Joi from "joi";

import { NextAuthPluginOptions } from "./types.js";
import * as Routes from "./routes.js";

const minimumProfileSchema = Joi.object()
  .keys({
    email: Joi.string().email().required(),
  })
  .unknown(true);

const minimumUserSchema = Joi.object()
  .keys({
    userId: Joi.string().required(),
    email: Joi.string().email().required(),
  })
  .unknown(true);

const minimumSessionSchema = Joi.object()
  .keys({
    id: Joi.string().required(),
    userId: Joi.string().required(),
    expires: Joi.number().required(),
    sessionToken: Joi.string().required(),
    accessToken: Joi.string().required(),
  })
  .unknown(true);

const defaultOptions = {
  basePath: "/api/nextauth",
  validators: {
    userId: Joi.string().required(),
    profile: minimumProfileSchema,
    user: minimumUserSchema,
    session: minimumSessionSchema,
  },
  tags: [],
};

const validateAuth = (sharedSecret) => (request, username, password) => {
  // we follow stripe's lead here for authenticating with basic auth
  // the shared secret should be bassed as the basic auth username, the password should be empty
  if (password !== "") {
    console.error(
      "hapi-nextauth: attempted authentication with basic auth password. only the username should be defined."
    );

    return { isValid: false, credentials: {} };
  }

  const isValid = username === sharedSecret;
  const credentials = {
    id: "nextauth-frontend",
  };

  return { isValid, credentials };
};

const register = async (
  server: Hapi.Server,
  pluginOpts?: any
): Promise<void> => {
  const options: any = Hoek.applyToDefaults(
    // a little type gymnastics here to workaround poor typing
    defaultOptions as any,
    pluginOpts
  ) as any;

  if (!options.nextAuthAdapterFactory) {
    throw new Error(
      "You must pass a NextAuthAdapterFactory instance to hapi-nextauth."
    );
  }

  server.validator(Joi);
  let auth = "hapi-nextauth";
  if (options.sharedSecret) {
    server.dependency(["@hapi/basic"]);
    server.auth.strategy(auth, "basic", {
      validate: validateAuth(options.sharedSecret),
    });
  } else {
    console.warn(
      "hapi-nextauth: AUTHENTICATION OF FRONTEND TO NEXTAUTH ENDPOINTS DISABLED!"
    );
    auth = undefined;
  }

  await Routes.register(server, options, auth);
};

const nextAuthPlugin = {
  register,
  name: "@digiresilience/hapi-nextauth",
  version: "0.0.3",
};

export * from "./types.js";
export default nextAuthPlugin;
