import { useSession } from "@tanstack/react-start/server";
import Passwordless from "supertokens-node/recipe/passwordless";
import SuperTokens from "supertokens-node";
import UserMetadata from "supertokens-node/recipe/usermetadata";
import { sendVerifyCode, updateVerify } from "@/lib/twilio";
import { resolveLocale } from "@/lib/i18n";

// The user isn't authenticated yet when the login code is sent, so the SMS
// locale comes from the stored preference of whichever user owns the phone
// number; new users fall back to English.
const getLocaleForPhone = async (phoneNumber: string): Promise<string> => {
  try {
    const users = await SuperTokens.listUsersByAccountInfo("public", {
      phoneNumber,
    });
    const userId = users[0]?.id;
    if (!userId) return "en";

    const { metadata } = await UserMetadata.getUserMetadata(userId);
    return resolveLocale(metadata?.locale);
  } catch {
    return "en";
  }
};

const init = () =>
  Passwordless.init({
    flowType: "USER_INPUT_CODE",
    contactMethod: "PHONE",
    smsDelivery: {
      override: (originalImplementation) => {
        return {
          ...originalImplementation,
          sendSms: async ({ userInputCode, phoneNumber, preAuthSessionId }) => {
            if (!userInputCode) {
              throw new Error("No user input code provided to sendSms");
            }

            const locale = await getLocaleForPhone(phoneNumber);
            const sid = await sendVerifyCode(phoneNumber, userInputCode, locale);

            const session = await useSession({
              password: preAuthSessionId,
            });

            await session.update({
              twilioSid: sid,
            });
          },
        };
      },
    },
    override: {
      functions: (originalImplementation) => {
        return {
          ...originalImplementation,
          consumeCode: async (input) => {
            const session = await useSession({
              password: input.preAuthSessionId,
            });
            const twilioSid = session?.data.twilioSid;

            if (!twilioSid) {
              throw new Error("Twilio SID not found in session");
            }

            let response = await originalImplementation.consumeCode(input);

            if (response.status === "OK") {
              await updateVerify(twilioSid);
              await session.update({
                twilioSid: undefined,
                userId: response?.user.id,
              });
            } else if (response.status === "INCORRECT_USER_INPUT_CODE_ERROR") {
              if (
                response.failedCodeInputAttemptCount !==
                response.maximumCodeInputAttempts
              ) {
                await updateVerify(twilioSid);
              }
            }

            return response;
          },
        };
      },
    },
  });

export default { init };
