import { CreateAuthChallengeTriggerEvent } from 'aws-lambda';
import { randomDigits } from 'crypto-secure-random-digit';
import { SES } from 'aws-sdk';
import { verifyText, verifyHTML } from './email';

export const createAuthChallengeHandler = async (event: CreateAuthChallengeTriggerEvent) => {
  try {
    const domain = process.env.DOMAIN;
    const fromAddress = process.env.FROM_ADDRESS;
    if (typeof domain !== 'string') {
      throw new Error('No DOMAIN defined in ENV');
    }
    if (typeof fromAddress !== 'string') {
      throw new Error('No FROM_ADDRESS defined in ENV');
    }

    let secretLoginCode: string;

    if (!event.request.session || !event.request.session.length) {
      // This is a new auth session
      // Generate a new secret login code and mail it to the user
      secretLoginCode = randomDigits(6).join('');

      await sendEmail(domain, event.request.userAttributes.email, secretLoginCode, fromAddress);
    } else {
      // There's an existing session. Don't generate new digits but
      // re-use the code from the current session. This allows the user to
      // make a mistake when keying in the code and to then retry, rather
      // the needing to e-mail the user an all new code again.
      const previousChallenge = event.request.session.slice(-1)[0];

      secretLoginCode = previousChallenge.challengeMetadata!.match(/CODE-(\d*)/)![1];
    }

    // This is sent back to the client app
    event.response.publicChallengeParameters = { email: event.request.userAttributes.email };

    // Add the secret login code to the private challenge parameters
    // so it can be verified by the "Verify Auth Challenge Response" trigger
    event.response.privateChallengeParameters = { secretLoginCode };

    // Add the secret login code to the session so it is available
    // in a next invocation of the "Create Auth Challenge" trigger
    event.response.challengeMetadata = `CODE-${secretLoginCode}`;

    return event;
  } catch (error) {
    console.error(JSON.stringify({ level: 'ERROR', error: error.message + '\n' + error.stack }));
    throw error;
  }
};

async function sendEmail(
  domain: string,
  emailAddress: string,
  secretLoginCode: string,
  fromAddress: string
) {
  const params: SES.SendEmailRequest = {
    Destination: { ToAddresses: [emailAddress] },
    Message: {
      Body: {
        Html: {
          Charset: 'UTF-8',
          Data: verifyHTML(domain, secretLoginCode),
        },
        Text: {
          Charset: 'UTF-8',
          Data: verifyText(secretLoginCode),
        },
      },
      Subject: {
        Charset: 'UTF-8',
        Data: 'Office Booker - Verify',
      },
    },
    Source: fromAddress,
  };

  console.log(JSON.stringify(params, null, 2));

  const ses = new SES();

  await ses.sendEmail(params).promise();
}