import { createContext } from "@tailor-platform/erp-kit/app";
import { createResolver, t } from "@tailor-platform/sdk";
import { getDB } from "@/generated/kysely-tailordb";
import { umModules } from "@/modules";

export default createResolver({
  name: "updateUserProfile",
  operation: "mutation",
  input: {
    userId: t.uuid().description("ID of the user to update"),
    name: t.string({ optional: true }).description("New display name"),
    email: t.string({ optional: true }).description("New email address"),
  },
  body: async (context) => {
    const db = getDB("main-db");
    let oldEmail: string | undefined;

    const result = await db.transaction().execute(async (trx) => {
      const oldUser = await trx
        .selectFrom("User")
        .select(["email"])
        .where("id", "=", context.input.userId)
        .executeTakeFirst();
      if (oldUser) {
        oldEmail = oldUser.email;
      }

      const cmdResult = await umModules.commands.updateUser(
        trx,
        {
          id: context.input.userId,
          name: context.input.name ?? undefined,
          email: context.input.email ?? undefined,
        },
        createContext(context),
      );
      if (!cmdResult.ok) {
        switch (cmdResult.error.code) {
          case "USER_MANAGEMENT_USER_NOT_FOUND":
            throw new Error(`User ${context.input.userId} does not exist`);
          case "USER_MANAGEMENT_USER_ALREADY_EXISTS":
            throw new Error(`A user with email ${context.input.email} already exists`);
          case "USER_MANAGEMENT_MISSING_REQUIRED_FIELD":
            throw new Error("At least one of name or email must be provided");
          case "USER_MANAGEMENT_INVALID_NAME":
            throw new Error("Name must not be empty");
          case "USER_MANAGEMENT_INVALID_EMAIL":
            throw new Error(`Invalid email format: ${context.input.email}`);
          case "INSUFFICIENT_PERMISSION":
            throw cmdResult.error;
          default:
            throw cmdResult.error satisfies never;
        }
      }

      // IDP uses email as the username — sync when email changes
      if (context.input.email != null && context.input.email !== oldEmail) {
        const idpClient = new tailor.idp.Client({ namespace: "default" });
        const idpUser = (await idpClient.users({ query: { names: [oldEmail!] } })).users[0];
        if (idpUser) {
          await idpClient.updateUser({ id: idpUser.id, name: context.input.email });
        }
      }

      return {
        id: cmdResult.value.user.id,
        name: cmdResult.value.user.name,
        email: cmdResult.value.user.email,
      };
    });

    return result;
  },
  output: t
    .object({
      id: t.uuid().description("User ID"),
      name: t.string().description("Updated name"),
      email: t.string().description("Updated email"),
    })
    .description("Updated user profile"),
});
