<?php
/**
 * Provisioner — création/synchronisation d'utilisateurs applicatifs déclarés
 * par les modules (auto‑contenu, idempotent).
 *
 * Un module déclare dans son descripteur (module.php) une clé optionnelle :
 *
 *   'provision_users' => [
 *       ['username' => 'reporting', 'email' => '', 'roles' => ['oracle_user'],
 *        'auth_method' => AUTH_LOCAL /* défaut *\/, 'password' => '' /* optionnel *\/],
 *       ...
 *   ],
 *
 * Quand le module est actif (activation ou resynchronisation), pour chaque
 * entrée : l'utilisateur est créé s'il n'existe pas, puis ses rôles déclarés
 * lui sont attribués (jamais retirés). Idempotent : un 2ᵉ passage ne fait rien.
 *
 * Mot de passe : si auth local sans mot de passe fourni, le compte est créé
 * désactivé (active=0) en attente d'une réinitialisation par l'administrateur ;
 * pour LDAP/OAuth (auth externe) le compte est actif.
 */
class Provisioner
{
    /**
     * Synchronise les utilisateurs déclarés par un module.
     * @return array{created:int, roles:int, skipped:int, errors:string[]}
     */
    public static function syncModule(Module $registry, User $users, string $name): array
    {
        $report = ['created' => 0, 'roles' => 0, 'skipped' => 0, 'errors' => []];

        $desc = $registry->get($name);
        $list = $desc['provision_users'] ?? [];
        if (!is_array($list) || empty($list)) return $report;

        $validRoles = array_column($users->getAllRoles(), 'name');

        foreach ($list as $u) {
            $username = trim((string)($u['username'] ?? ''));
            if ($username === '') { $report['errors'][] = 'username manquant'; continue; }

            $existing = $users->findByUsername($username);
            if (!$existing) {
                $authMethod = (string)($u['auth_method'] ?? AUTH_LOCAL);
                $hasPass    = !empty($u['password']);
                $data = [
                    'username'    => $username,
                    'email'       => $u['email'] ?? null,
                    'auth_method' => $authMethod,
                    'active'      => ($authMethod === AUTH_LOCAL && !$hasPass) ? 0 : 1,
                ];
                if ($hasPass) $data['password'] = (string)$u['password'];

                $id = $users->create($data);
                if ($id === false) { $report['errors'][] = "création échouée : {$username}"; continue; }
                $report['created']++;
                $userId = (int)$id;
            } else {
                $report['skipped']++;
                $userId = (int)$existing['id'];
            }

            foreach ((array)($u['roles'] ?? []) as $role) {
                $role = (string)$role;
                if (!in_array($role, $validRoles, true)) {
                    $report['errors'][] = "rôle inconnu : {$role}";
                    continue;
                }
                $users->addRole($userId, $role);
                $report['roles']++;
            }
        }

        return $report;
    }

    /** Synchronise tous les modules actifs. */
    public static function syncAllActive(Module $registry, User $users): array
    {
        $agg = ['created' => 0, 'roles' => 0, 'skipped' => 0, 'errors' => []];
        foreach ($registry->getAll() as $m) {
            if (empty($m['active'])) continue;
            $r = self::syncModule($registry, $users, (string)($m['name'] ?? ''));
            $agg['created'] += $r['created'];
            $agg['roles']   += $r['roles'];
            $agg['skipped'] += $r['skipped'];
            $agg['errors']   = array_merge($agg['errors'], $r['errors']);
        }
        return $agg;
    }
}
