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: "updateUserRoles",
  operation: "mutation",
  input: {
    userId: t.uuid().description("User ID"),
    roleIds: t.uuid({ array: true }).description("Desired role IDs"),
  },
  body: async (context) => {
    const db = getDB("main-db");
    const result = await db.transaction().execute(async (trx) => {
      const ctx = createContext(context);

      // Get current role assignments
      const currentAssignments = await trx
        .selectFrom("UserRole")
        .select("roleId")
        .where("userId", "=", context.input.userId)
        .execute();

      const currentIds = new Set(currentAssignments.map((a) => a.roleId));
      const desiredIds = new Set(context.input.roleIds);

      const toAssign = [...desiredIds].filter((id) => !currentIds.has(id));
      const toRevoke = [...currentIds].filter((id) => !desiredIds.has(id));

      for (const roleId of toAssign) {
        const r = await umModules.commands.assignRoleToUser(
          trx,
          { userId: context.input.userId, roleId },
          ctx,
        );
        if (!r.ok) {
          switch (r.error.code) {
            case "USER_MANAGEMENT_USER_NOT_FOUND":
              throw new Error(`User ${context.input.userId} does not exist`);
            case "USER_MANAGEMENT_USER_NOT_ACTIVE":
              throw new Error(`User ${context.input.userId} is not active`);
            case "USER_MANAGEMENT_ROLE_NOT_FOUND":
              throw new Error(`Role ${roleId} does not exist`);
            case "USER_MANAGEMENT_ROLE_NOT_ACTIVE":
              throw new Error(`Role ${roleId} is not active`);
            case "INSUFFICIENT_PERMISSION":
              throw r.error;
            default:
              throw r.error satisfies never;
          }
        }
      }

      for (const roleId of toRevoke) {
        const r = await umModules.commands.revokeRoleFromUser(
          trx,
          { userId: context.input.userId, roleId },
          ctx,
        );
        if (!r.ok) {
          switch (r.error.code) {
            case "USER_MANAGEMENT_USER_NOT_FOUND":
              throw new Error(`User ${context.input.userId} does not exist`);
            case "USER_MANAGEMENT_ROLE_NOT_FOUND":
              throw new Error(`Role ${roleId} does not exist`);
            case "USER_MANAGEMENT_ASSIGNMENT_NOT_FOUND":
              break;
            case "INSUFFICIENT_PERMISSION":
              throw r.error;
            default:
              throw r.error satisfies never;
          }
        }
      }

      return { userId: context.input.userId };
    });

    return { userId: result.userId };
  },
  output: t
    .object({
      userId: t.uuid().description("User ID"),
    })
    .description("User roles update result"),
});
