import * as db from "./db";

const SALLE_SIGNATURE_DELEGATION_SETTING_KEY = "system.salle_signature.delegations";

type DirectriceDelegationEntry = {
  delegateUserIds: number[];
};

type SalleSignatureDelegationSettings = {
  directriceDelegations: Record<string, DirectriceDelegationEntry>;
};

function sanitizeUserIds(values: unknown): number[] {
  if (!Array.isArray(values)) return [];
  return Array.from(
    new Set(
      values
        .map((value) => Number(value))
        .filter((value) => Number.isInteger(value) && value > 0)
    )
  );
}

function sanitizeSettings(value: unknown): SalleSignatureDelegationSettings {
  if (!value || typeof value !== "object") {
    return { directriceDelegations: {} };
  }

  const record = (value as { directriceDelegations?: unknown }).directriceDelegations;
  if (!record || typeof record !== "object") {
    return { directriceDelegations: {} };
  }

  const entries = Object.entries(record as Record<string, unknown>).reduce<Record<string, DirectriceDelegationEntry>>(
    (acc, [directriceId, entry]) => {
      const userId = Number(directriceId);
      if (!Number.isInteger(userId) || userId <= 0) return acc;
      const delegateUserIds = sanitizeUserIds((entry as { delegateUserIds?: unknown })?.delegateUserIds);
      acc[String(userId)] = { delegateUserIds };
      return acc;
    },
    {}
  );

  return { directriceDelegations: entries };
}

export async function getSalleSignatureDelegationSettings(): Promise<SalleSignatureDelegationSettings> {
  const raw = await db.getPortalSetting(SALLE_SIGNATURE_DELEGATION_SETTING_KEY);
  if (!raw) {
    return { directriceDelegations: {} };
  }

  try {
    return sanitizeSettings(JSON.parse(raw));
  } catch {
    return { directriceDelegations: {} };
  }
}

export async function saveSalleSignatureDelegationSettings(settings: SalleSignatureDelegationSettings) {
  await db.setPortalSetting(
    SALLE_SIGNATURE_DELEGATION_SETTING_KEY,
    JSON.stringify(sanitizeSettings(settings)),
    "Délégations de signature des demandes de salle"
  );
}

export async function getDelegatedSignerIdsForDirectrice(directriceUserId: number) {
  const settings = await getSalleSignatureDelegationSettings();
  return settings.directriceDelegations[String(directriceUserId)]?.delegateUserIds || [];
}

export async function setDelegatedSignerIdsForDirectrice(directriceUserId: number, delegateUserIds: number[]) {
  const settings = await getSalleSignatureDelegationSettings();
  settings.directriceDelegations[String(directriceUserId)] = {
    delegateUserIds: sanitizeUserIds(delegateUserIds),
  };
  await saveSalleSignatureDelegationSettings(settings);
}

export async function addDelegatedSignerForDirectrice(directriceUserId: number, delegateUserId: number) {
  const current = await getDelegatedSignerIdsForDirectrice(directriceUserId);
  const next = Array.from(new Set([...current, delegateUserId]));
  await setDelegatedSignerIdsForDirectrice(directriceUserId, next);
  return next;
}

export async function removeDelegatedSignerForDirectrice(directriceUserId: number, delegateUserId: number) {
  const current = await getDelegatedSignerIdsForDirectrice(directriceUserId);
  const next = current.filter((entry) => entry !== delegateUserId);
  await setDelegatedSignerIdsForDirectrice(directriceUserId, next);
  return next;
}

export async function getDirectriceIdsDelegatingToUser(userId: number) {
  const settings = await getSalleSignatureDelegationSettings();
  return Object.entries(settings.directriceDelegations)
    .filter(([, entry]) => sanitizeUserIds(entry.delegateUserIds).includes(userId))
    .map(([directriceId]) => Number(directriceId))
    .filter((value) => Number.isInteger(value) && value > 0);
}
