'use strict';

/**
 * Gestão isolada das permissões administrativas.
 *
 * Regras:
 * - a conta principal é a primeira conta criada nesta instalação;
 * - só a conta principal pode conceder ou retirar acesso administrativo;
 * - as permissões são guardadas por ID de utilizador, nunca pelo nome;
 * - nomes como "admin" ou "Edgar" não dão acesso automaticamente.
 */
(() => {
  const VERSION = 1;

  function validUsers(database) {
    return Array.isArray(database?.users) ? database.users : [];
  }

  function oldestUser(users) {
    return [...users].sort((a, b) => {
      const timeA = Number(new Date(a?.createdAt || 0)) || 0;
      const timeB = Number(new Date(b?.createdAt || 0)) || 0;
      if (timeA !== timeB) return timeA - timeB;
      return String(a?.id || '').localeCompare(String(b?.id || ''));
    })[0] || null;
  }

  function ensure(database) {
    if (!database || typeof database !== 'object') return null;
    if (!Array.isArray(database.users)) database.users = [];

    const users = validUsers(database);
    const validIds = new Set(users.map(user => user.id));
    const previous = database.adminAccess && typeof database.adminAccess === 'object'
      ? database.adminAccess
      : {};
    const strictServerOwner = previous.strictServerOwner === true;

    const access = {
      version: VERSION,
      strictServerOwner,
      ownerUsername: previous.ownerUsername || '',
      ownerUserId: validIds.has(previous.ownerUserId) ? previous.ownerUserId : null,
      adminUserIds: Array.isArray(previous.adminUserIds)
        ? [...new Set(previous.adminUserIds.filter(id => validIds.has(id)))]
        : []
    };

    // Em multiplayer, o dono vem do servidor/configuração.
    // Nunca dar Administração automaticamente ao primeiro jogador de um cliente descarregado.
    if (!access.ownerUserId && !strictServerOwner) access.ownerUserId = oldestUser(users)?.id || null;

    // Migração única das permissões explicitamente concedidas nas versões anteriores.
    // Os acessos antigos baseados apenas no nome não são importados.
    if (!previous.migratedExplicitFlags && !strictServerOwner) {
      users.forEach(user => {
        if (user?.isAdmin === true && user.id !== access.ownerUserId && !access.adminUserIds.includes(user.id)) {
          access.adminUserIds.push(user.id);
        }
        if (Object.prototype.hasOwnProperty.call(user || {}, 'isAdmin')) delete user.isAdmin;
      });
    }

    access.adminUserIds = access.adminUserIds.filter(id => id !== access.ownerUserId);
    access.migratedExplicitFlags = true;
    database.adminAccess = access;
    return access;
  }

  function isOwner(database, user) {
    const access = ensure(database);
    return Boolean(user?.id && access?.ownerUserId === user.id);
  }

  function isAdmin(database, user) {
    const access = ensure(database);
    return Boolean(user?.id && (access?.ownerUserId === user.id || access?.adminUserIds?.includes(user.id)));
  }

  function setAdmin(database, actor, targetUserId, enabled) {
    const access = ensure(database);
    if (!access) throw new Error('Não foi possível carregar as permissões administrativas.');
    if (!isOwner(database, actor)) throw new Error('Apenas a conta principal pode alterar os acessos administrativos.');
    if (!targetUserId) throw new Error('Seleciona um jogador válido.');
    if (targetUserId === access.ownerUserId) throw new Error('O acesso permanente da conta principal não pode ser removido.');

    const ids = new Set(access.adminUserIds || []);
    if (enabled) ids.add(targetUserId);
    else ids.delete(targetUserId);
    access.adminUserIds = [...ids];
    database.adminAccess = access;
    return enabled;
  }

  function owner(database) {
    const access = ensure(database);
    return validUsers(database).find(user => user.id === access?.ownerUserId) || null;
  }

  globalThis.ReinosAdminPermissions = Object.freeze({
    VERSION,
    ensure,
    owner,
    isOwner,
    isAdmin,
    setAdmin
  });
})();
