import {
  type TailordbKysely,
  type Transaction as KyselyTransaction,
} from "@tailor-platform/sdk/kysely";
import { DB } from "../generated/kysely-tailordb";
import { User } from "./types";

export const recomputeUserPermissions = async <
  T extends {
    User: object;
    UserRole: object;
    Role: object;
  },
>(
  db: TailordbKysely<T> | KyselyTransaction<T>,
  userId: string,
): Promise<User<T>> => {
  const _db = db as unknown as DB;

  // Get all Role.permissions arrays for a user's roles
  const roles = await _db
    .selectFrom("UserRole")
    .innerJoin("Role", "Role.id", "UserRole.roleId")
    .select("Role.permissions")
    .where("UserRole.userId", "=", userId)
    .where("Role.status", "=", "ACTIVE")
    .execute();

  // Flatten all permissions arrays, deduplicate, sort
  const permissions = [...new Set(roles.flatMap((r) => r.permissions ?? []))].sort();

  const updatedUser = await _db
    .updateTable("User")
    .set({ permissions, updatedAt: new Date() })
    .where("id", "=", userId)
    .returningAll()
    .executeTakeFirstOrThrow();

  return updatedUser as unknown as User<T>;
};

export const recomputePermissionsForUsersWithRole = async <
  T extends {
    User: object;
    UserRole: object;
    Role: object;
  },
>(
  db: TailordbKysely<T> | KyselyTransaction<T>,
  roleId: string,
): Promise<User<T>[]> => {
  const _db = db as unknown as DB;

  const userRoles = await _db
    .selectFrom("UserRole")
    .select("userId")
    .where("roleId", "=", roleId)
    .execute();

  const updatedUsers: User<T>[] = [];
  for (const { userId } of userRoles) {
    const user = await recomputeUserPermissions(db, userId);
    updatedUsers.push(user);
  }
  return updatedUsers;
};
