'use strict';

const passport = require('koa-passport');

const utils = require('./utils');

const defaultConnectionError = () => new Error('Invalid connection payload');

const authenticate = async (ctx, next) => {
  const {
    params: { provider },
  } = ctx;
  const redirectUrls = utils.getPrefixedRedirectUrls();

  return passport.authenticate(provider, null, async (error, profile) => {
    if (error || !profile || !profile.email) {
      if (error) {
        strapi.log.error(error);
      }

      strapi.eventHub.emit('admin.auth.error', {
        error: error || defaultConnectionError(),
        provider,
      });

      return ctx.redirect(redirectUrls.error);
    }

    const user = await strapi.admin.services.user.findOne({ email: profile.email });
    const scenario = user ? existingUserScenario : nonExistingUserScenario;

    return scenario(ctx, next)(user || profile, provider);
  })(ctx, next);
};

const existingUserScenario = (ctx, next) => async (user, provider) => {
  const redirectUrls = utils.getPrefixedRedirectUrls();

  if (!user.isActive) {
    strapi.eventHub.emit('admin.auth.error', {
      error: new Error(`Deactivated user tried to login (${user.id})`),
      provider,
    });
    return ctx.redirect(redirectUrls.error);
  }

  ctx.state.user = user;
  return next();
};

const nonExistingUserScenario = (ctx, next) => async (profile, provider) => {
  const { email, firstname, lastname, username } = profile;
  const redirectUrls = utils.getPrefixedRedirectUrls();
  const adminStore = await utils.getAdminStore();
  const { providers } = await adminStore.get({ key: 'auth' });

  // We need at least the username or the firstname/lastname combination to register a new user
  const isMissingRegisterFields = !username && (!firstname || !lastname);

  if (!providers.autoRegister || !providers.defaultRole || isMissingRegisterFields) {
    strapi.eventHub.emit('admin.auth.error', { error: defaultConnectionError(), provider });
    return ctx.redirect(redirectUrls.error);
  }

  const defaultRole = await strapi.admin.services.role.findOne({ id: providers.defaultRole });

  // If the default role has been misconfigured, redirect with an error
  if (!defaultRole) {
    strapi.eventHub.emit('admin.auth.error', { error: defaultConnectionError(), provider });
    return ctx.redirect(redirectUrls.error);
  }

  // Register a new user with the information given by the provider and login with it
  ctx.state.user = await strapi.admin.services.user.create({
    email,
    username,
    firstname,
    lastname,
    roles: [defaultRole.id],
    isActive: true,
    registrationToken: null,
  });

  strapi.eventHub.emit('admin.auth.autoRegistration', {
    user: ctx.state.user,
    provider,
  });

  return next();
};

const redirectWithAuth = ctx => {
  const {
    params: { provider },
  } = ctx;
  const redirectUrls = utils.getPrefixedRedirectUrls();
  const { user } = ctx.state;

  const jwt = strapi.admin.services.token.createJwtToken(user);

  const isProduction = strapi.config.environment === 'production';

  const cookiesOptions = { httpOnly: false, secure: isProduction, overwrite: true };

  strapi.eventHub.emit('admin.auth.success', { user, provider });

  ctx.cookies.set('jwtToken', jwt, cookiesOptions);
  ctx.redirect(redirectUrls.success);
};

module.exports = {
  authenticate,
  redirectWithAuth,
};
