import type { User } from "../drizzle/schema";
import * as db from "./db";
import { userHasLogisticsAccess } from "./logisticsGroup";
import {
  getDelegatedSignerIdsForDirectrice,
  getDirectriceIdsDelegatingToUser,
} from "./salleSignatureDelegation";

export type AuthenticatedPortalUser = User & {
  canManageLogistics: boolean;
  canSignSalle: boolean;
  salleSignatureDelegatedByUserIds: number[];
};

type MinimalUser = Pick<User, "id" | "role" | "canManageLogistics">;

export async function userHasSalleSignatureAccess(user: Pick<User, "id" | "role">) {
  if (user.role === "super_admin" || user.role === "directrice") {
    return true;
  }

  const [internalUsers, delegatedBySetting] = await Promise.all([
    db.getAdminUsers(),
    getDirectriceIdsDelegatingToUser(user.id),
  ]);

  return internalUsers.some((entry) => {
    if (entry.role !== "directrice" || !entry.isActive) return false;
    return entry.delegatedSalleSignerUserId === user.id || delegatedBySetting.includes(entry.id);
  });
}

export async function getSalleSignatureDelegatedByUserIds(userId: number) {
  const [internalUsers, delegatedBySetting] = await Promise.all([
    db.getAdminUsers(),
    getDirectriceIdsDelegatingToUser(userId),
  ]);

  return Array.from(
    new Set(
      internalUsers
    .filter(
      (entry) =>
        entry.role === "directrice"
        && entry.isActive
        && entry.delegatedSalleSignerUserId === userId
    )
    .map((entry) => entry.id)
        .concat(delegatedBySetting)
    )
  );
}

export async function withEffectiveInternalAccess<TUser extends User | null>(
  user: TUser
): Promise<(AuthenticatedPortalUser & NonNullable<TUser>) | null> {
  if (!user) return null;

  const [effectiveLogisticsAccess, effectiveSalleSignatureAccess, delegatedByUserIds] =
    await Promise.all([
      userHasLogisticsAccess(user as MinimalUser),
      userHasSalleSignatureAccess(user),
      getSalleSignatureDelegatedByUserIds(user.id),
    ]);

  return {
    ...user,
    canManageLogistics: effectiveLogisticsAccess,
    canSignSalle: effectiveSalleSignatureAccess,
    salleSignatureDelegatedByUserIds: delegatedByUserIds,
  } as AuthenticatedPortalUser & NonNullable<TUser>;
}

export async function getSalleSignatureDelegateCandidates(currentUserId: number) {
  const internalUsers = await db.getAdminUsers();
  return internalUsers
    .filter(
      (entry) =>
        entry.isActive
        && entry.id !== currentUserId
        && (
          entry.role === "accueil"
          || entry.role === "admin"
          || entry.role === "directrice"
          || entry.role === "super_admin"
        )
    )
    .map((entry) => ({
      id: entry.id,
      name: entry.name || "Sans nom",
      email: entry.email || "",
      role: entry.role,
    }));
}

export async function getSalleSignatureDelegates(directriceUserId: number) {
  const delegateIds = await getDelegatedSignerIdsForDirectrice(directriceUserId);
  const delegates = await Promise.all(delegateIds.map((id) => db.getUserById(id)));

  return delegates
    .filter((entry): entry is NonNullable<typeof entry> => Boolean(entry?.isActive))
    .map((entry) => ({
      id: entry.id,
      name: entry.name || "Sans nom",
      email: entry.email || "",
      role: entry.role,
    }));
}
