/**
 * Try to get door info
 */

import { ServerlessEventObject, ServerlessFunctionSignature } from "@twilio-labs/serverless-runtime-types/types";
import { TwilioContext } from "../../../types/TwilioContext";
import { createDynaBridgeClient } from "../../../utils/ddb";
import { ONBOARDING_DOOR_NAME } from "../../../schema/DoorConfig";
import { getLockStatusID, isLockOpen } from "../../../schema/LockStatus";
import { withMetrics } from "../../../common/DoormanHandler";
import { z } from "zod";
import { UserAgentHeader } from "../../../utils/blockUserAgent";
import { setResponseJson } from "../../../utils/responseUtils";
import { LOG_CALL_SK, LogCallSchema } from "../../../schema/LogCall";

import crypto from "crypto";
import { sanitizePhoneNumber } from "../../../utils/phoneUtils";
import { getFutureTTLInSeconds } from "../../../common/TTLHelper";

export const LogCallRequestSchema = z.object({
  caller: z.string(),
});

export type LogCallRequest = z.infer<typeof LogCallRequestSchema>;
export interface LogCallRequestTwilio extends ServerlessEventObject<LogCallRequest, UserAgentHeader> { };

export const LogCallResponseSchema = z.object({
  otp: z.string(),
});

export type LogCallResponse = z.infer<typeof LogCallResponseSchema>;

// hash is 4 digit number based on todays date + phone number caller
// cost saving so we don't generate a new OTP for every caller even if its the same caller
function getCode(caller: string) {
  const hash = crypto.createHash("sha256");
  const today = new Date();

  hash.update(today.toLocaleDateString('en-US'));
  hash.update(caller);

  const hashHex = hash.digest('hex');

  // 2. Convert the hexadecimal string to a BigInt
  //    This is necessary for large hash values that exceed JavaScript's Number limit.
  const hashBigInt = BigInt(`0x${hashHex}`);

  // 3. Convert the BigInt to a decimal string
  const hashDecimal = hashBigInt.toString();
  return hashDecimal.substring(hashDecimal.length - 4,);
};

export const handler: ServerlessFunctionSignature<TwilioContext, LogCallRequestTwilio> = withMetrics("logCall", async (context, event, callback, metricsRegistry) => {
  const response = new Twilio.Response();
  const req = LogCallRequestSchema.parse(event);

  let caller = sanitizePhoneNumber(req.caller);

  const db = createDynaBridgeClient(context);

  // check if onboarding is actually open
  const lock = await db.entities.lockStatus.findById(getLockStatusID(ONBOARDING_DOOR_NAME));

  if (!isLockOpen(lock)) {
    setResponseJson(response, 400, {
      msg: "Onboarding is not open",
    });
  } else {
    // log this caller
    const otp = getCode(caller);
    const logCall = LogCallSchema.parse({
      PK: otp,
      SK: LOG_CALL_SK,
      caller,
      TTL: getFutureTTLInSeconds(60 * 60), // 60 minutes from now
    });

    await db.entities.logCall.save(logCall);

    setResponseJson(response, 200, {
      otp,
    });
  }

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

  return callback(null, response);
});
