
/**
 * Edit API for doors
 */

import { ServerlessEventObject, ServerlessFunctionSignature } from "@twilio-labs/serverless-runtime-types/types";
import { TwilioContext } from "../../../types/TwilioContext";
import { shouldBlockRequest, UserAgentHeader } from "../../../utils/blockUserAgent";
import { createDynaBridgeClient } from "../../../utils/ddb";
import { sendMessageToUser } from "../../../utils/discord";
import { createEditDoorConfig, EditDoorConfigReq, editDoorToDoorConfig, getDoorConfigID, getEditDoorConfigID } from "../../../schema/DoorConfig";

export interface EditRequest extends ServerlessEventObject<{}, UserAgentHeader> {
  door?: string;
  approvalId?: string;
  newConfig?: string;
}

export const handler: ServerlessFunctionSignature<TwilioContext, EditRequest> = async function(context, event, callback) {
  const response = new Twilio.Response();

  if (shouldBlockRequest(event)) {
    response.setStatusCode(200);
    return callback(null, response);
  }

  let door = event.door;
  let approvalId = event.approvalId;
  let newConfigString = event.newConfig;

  const db = createDynaBridgeClient(context);

  // approve path
  if (door && approvalId) {
    const newConfig = await db.entities.editDoorConfig.findById(getEditDoorConfigID(door));

    if (!newConfig || newConfig.approvalId !== approvalId) {
      response.setStatusCode(400);
      return callback(null, response);
    }

    db.entities.doorConfig.save(editDoorToDoorConfig(newConfig));

    // send update to discord users
    const updateMessage = `Configuration change \`${approvalId}\` was approved @ Door "${door}"`;

    const discordPromises = newConfig.discordUsers.map((user) => {
      return sendMessageToUser(
        context,
        user,
        updateMessage,
      ).catch(e => console.error(e))
    });

    await Promise.all(discordPromises);

    response.setStatusCode(200);
    return callback(null, response);
  }

  if (!door || !newConfigString) {
    response.setStatusCode(400);
    return callback(null, response);
  }

  const newConfig: EditDoorConfigReq = JSON.parse(newConfigString);
  const config = await db.entities.doorConfig.findById(getDoorConfigID(door));

  if (!config) {
    response.setStatusCode(404);
    return callback(null, response);
  }

  // set to old PIN if it is missing
  if (newConfig.pin === "") {
    newConfig.pin = config.pin;
  }

  const editDoorConfig = createEditDoorConfig(door, newConfig);
  await db.entities.editDoorConfig.save(editDoorConfig);

  // newConfig.discordUsers = undefined;
  // newConfig.fallbackNumbers = undefined;
  // newConfig.status = undefined;

  const approvalUrl = `https://doorman.chromart.cc/api/door/edit?door=${door}&approvalId=${editDoorConfig.approvalId as string}`;
  console.log(approvalUrl);

  // send update to discord users
  const approvalMessage = `Configuration change requested @ Door "${door}" [click to approve it](${approvalUrl})\`\`\`${JSON.stringify(newConfig, null, 4)}\`\`\``;

  const discordPromises = config.discordUsers.map((user) => {
    return sendMessageToUser(
      context,
      user,
      approvalMessage,
    ).catch(e => console.error(e))
  });

  await Promise.all(discordPromises);

  response
    .setStatusCode(200)
    .appendHeader('Content-Type', 'application/json')
    .setBody({ msg: "Created Configuration change" });

  // destroy the internal client after
  // @ts-ignore
  db.ddbClient.destroy();

  return callback(null, response);
};
