<?php
/**
 * Fichier  : api/users.php
 * Auteur   : KREMER Régis
 * Version  : 2.6.119
 * Date     : 2026-07-25
 * Description : API REST — Gestion des utilisateurs locaux et affichage sécurisé des comptes LDAP.
 *
 * Changelog :
 *   v2.2.0 (2026-02-21) — Permissions magasins et gestion des comptes locaux.
 *   v2.6.102 (2026-07-21) — Sources d’authentification, protection du dernier admin local et comptes LDAP non éditables localement.
 *   v2.6.111 (2026-07-22) — Autorisations LDAP synchronisées ou surchargées localement, avec restauration de l’instantané annuaire.
 *   v2.6.113 (2026-07-22) — Ajout du rôle Magasinier pour les comptes locaux et LDAP.
 *   v2.6.119 (2026-07-25) — Politique commune, version de session et éligibilité à la récupération locale.
 */
require_once dirname(__DIR__).'/config.php';
require_once dirname(__DIR__).'/includes/ldap-helper.php';
startSession(); requireAdmin(); requirePerm('users.manage');
if($_SERVER['REQUEST_METHOD'] !== 'GET') csrfCheck();
$method=$_SERVER['REQUEST_METHOD'];
$body=json_decode(file_get_contents('php://input'),true)??[];

function usersApiPublic(array $u): array {
    unset($u['password'], $u['ldapDirectoryPermissions']);
    $u['authSource'] = ($u['authSource'] ?? 'local') === 'ldap' ? 'ldap' : 'local';
    $u['passwordManagedExternally'] = $u['authSource'] === 'ldap';
    $u['authStatus'] = $u['authSource'] === 'ldap' ? (string)($u['ldapStatus'] ?? 'active') : 'local';
    $u['authorizationSource'] = $u['authSource'] === 'ldap' ? magestockLdapAuthorizationSource($u) : 'local';
    $u['authorizationManagedBy'] = $u['authorizationSource'] === 'directory' ? 'directory' : 'magestock';
    $u['recoveryEligible'] = $u['authSource'] === 'local' && ($u['active'] ?? true) !== false;
    unset($u['authVersion']);
    return $u;
}
function usersApiFind(array $users, $id): ?array {
    foreach($users as $u) if((string)($u['id']??'')===(string)$id) return $u;
    return null;
}
function usersApiWouldRemoveLastLocalAdmin(array $users, $targetId, array $changes=[], bool $deleting=false): bool {
    $count=0;
    foreach($users as $u){
        if((string)($u['id']??'')===(string)$targetId){
            if($deleting) continue;
            $u=array_merge($u,$changes);
        }
        if(($u['authSource']??'local')!=='ldap'&&($u['active']??true)!==false&&($u['role']??'')==='admin'&&trim((string)($u['password']??''))!=='') $count++;
    }
    return $count<1;
}
function usersApiWarehouseIds($raw): array {
    if(is_string($raw)) $raw=json_decode($raw,true)?:[];
    if(!is_array($raw)) return [];
    return array_values(array_unique(array_filter(array_map('intval',$raw),fn($id)=>$id>0)));
}
function usersApiCurrentPermissionOverrides($id): array {
    $perms = loadPermissions();
    $raw = $perms['users'][(string)$id] ?? [];
    return magestockLdapNormalizePermissions(is_array($raw) ? $raw : []);
}
function usersApiSavePermissionOverrides($id, array $permissions): void {
    $perms = loadPermissions();
    $perms['users'][(string)$id] = magestockLdapNormalizePermissions($permissions);
    savePermissions($perms);
}

switch($method){
case 'GET':
    jsonResponse(array_map('usersApiPublic',loadData('users')));

case 'POST':
    $username=magestockLdapLower(trim((string)($body['username']??'')));
    $name=trim((string)($body['name']??''));
    $role=magestockNormalizeRole($body['role']??'user');
    $password=(string)($body['password']??'');
    if($username===''||$name===''||$password==='') jsonError('Tous les champs requis.');
    $passwordErrors = magestockPasswordPolicyErrors($password, ['username'=>$username,'name'=>$name]);
    if($passwordErrors) jsonError(implode(' ', $passwordErrors), 422);
    foreach(loadData('users') as $u) if(magestockLdapLower((string)($u['username']??''))===$username) jsonError('Identifiant déjà utilisé.');
    $item=addItem('users',[
        'username'=>$username,'name'=>$name,'role'=>$role,'password'=>password_hash($password,PASSWORD_DEFAULT),
        'active'=>true,'allowedWarehouses'=>usersApiWarehouseIds($body['allowedWarehouses']??[]),'authSource'=>'local','authVersion'=>1
    ]);
    jsonResponse(usersApiPublic($item),201);

case 'PUT':
    $id=$body['id']??null;
    if(!$id) jsonError('ID manquant.');
    $users=loadData('users');
    $target=usersApiFind($users,$id);
    if(!$target) jsonError('Non trouvé.',404);
    $isLdap=(($target['authSource']??'local')==='ldap');
    $fields=[];
    if($isLdap){
        if(isset($body['password'])&&$body['password']!=='') jsonError('Le mot de passe est géré par l’annuaire LDAP.',422);
        if(isset($body['name'])) jsonError('Le nom de ce compte est synchronisé depuis LDAP.',422);

        $currentSource = magestockLdapAuthorizationSource($target);
        $requestedSource = isset($body['authorizationSource'])
            ? (((string)$body['authorizationSource'] === 'local') ? 'local' : 'directory')
            : $currentSource;
        $currentPermissions = usersApiCurrentPermissionOverrides($id);

        if($requestedSource === 'local'){
            if($currentSource !== 'local'){
                $fields['ldapDirectoryRole'] = magestockNormalizeRole($target['role']??'user');
                $fields['ldapDirectoryAllowedWarehouses'] = usersApiWarehouseIds($target['allowedWarehouses']??[]);
                $fields['ldapDirectoryPermissions'] = $currentPermissions;
            }
            $fields['authorizationSource']='local';
            if(isset($body['role'])) $fields['role']=magestockNormalizeRole($body['role']);
            if(isset($body['allowedWarehouses'])) $fields['allowedWarehouses']=usersApiWarehouseIds($body['allowedWarehouses']);
            $fields['authorizationOverrideUpdatedAt']=date('c');
            $fields['authorizationOverrideUpdatedBy']=currentUser()['id']??null;
        } else {
            $fields['authorizationSource']='directory';
            $fields['role']=magestockNormalizeRole($target['ldapDirectoryRole']??$target['role']??'user');
            $fields['allowedWarehouses']=usersApiWarehouseIds($target['ldapDirectoryAllowedWarehouses']??$target['allowedWarehouses']??[]);
            usersApiSavePermissionOverrides($id, is_array($target['ldapDirectoryPermissions']??null)?$target['ldapDirectoryPermissions']:$currentPermissions);
            $fields['authorizationOverrideUpdatedAt']=date('c');
            $fields['authorizationOverrideUpdatedBy']=currentUser()['id']??null;
        }
        if(isset($body['active'])) $fields['active']=(bool)$body['active'];
    } else {
        if(isset($body['name'])) $fields['name']=trim((string)$body['name']);
        if(isset($body['role'])) $fields['role']=magestockNormalizeRole($body['role']);
        if(isset($body['active'])) $fields['active']=(bool)$body['active'];
        if(isset($body['password'])&&$body['password']!==''){
            $candidatePassword=(string)$body['password'];
            $passwordErrors=magestockPasswordPolicyErrors($candidatePassword,$target);
            if(password_verify($candidatePassword,(string)($target['password']??''))) $passwordErrors[]='Le nouveau mot de passe doit être différent du mot de passe actuel.';
            if($passwordErrors) jsonError(implode(' ',$passwordErrors),422);
            $fields['password']=password_hash($candidatePassword,PASSWORD_DEFAULT);
            $fields['authVersion']=magestockUserAuthVersion($target)+1;
            $fields['passwordChangedAt']=date('c');
            $fields['mustChangePassword']=false;
        }
        if(isset($body['allowedWarehouses'])) $fields['allowedWarehouses']=usersApiWarehouseIds($body['allowedWarehouses']);
    }
    if(isset($fields['active'])&&!$fields['active']&&(string)$id===(string)$_SESSION['user_id']) jsonError('Impossible de se désactiver.');
    if(!$isLdap&&usersApiWouldRemoveLastLocalAdmin($users,$id,$fields,false)) jsonError('Impossible de retirer le dernier administrateur local de secours.',422);
    $up=updateItem('users',$id,$fields);
    if($isLdap && isset($fields['authorizationSource'])){
        magestockLdapAudit('authorization_source_changed', [
            'targetUserId'=>$id,
            'username'=>$target['username']??'',
            'from'=>$currentSource??'directory',
            'to'=>$fields['authorizationSource'],
            'role'=>$up['role']??'user',
        ], currentUser());
    }
    jsonResponse(usersApiPublic($up));

case 'DELETE':
    $id=$body['id']??$_GET['id']??null;
    if(!$id) jsonError('ID manquant.');
    if((string)$id===(string)$_SESSION['user_id']) jsonError('Impossible de supprimer votre compte.');
    $users=loadData('users');
    $target=usersApiFind($users,$id);
    if(!$target) jsonError('Non trouvé.',404);
    if(($target['authSource']??'local')!=='ldap'&&usersApiWouldRemoveLastLocalAdmin($users,$id,[],true)) jsonError('Impossible de supprimer le dernier administrateur local de secours.',422);
    deleteItem('users',$id);
    $perms=loadPermissions(); unset($perms['users'][(string)$id]); savePermissions($perms);
    jsonResponse(['ok'=>true]);

default: jsonError('Méthode non supportée.',405);
}
