<?php
function current_user() {
    static $cached = false;
    static $cachedUserId = 0;
    $sessionUserId = !empty($_SESSION['user_id']) ? (int)$_SESSION['user_id'] : 0;
    if ($cached !== false && $cachedUserId === $sessionUserId) return $cached;
    if ($sessionUserId < 1) {
        $cachedUserId = 0;
        return $cached = null;
    }
    $stmt = db()->prepare('SELECT u.*, c.name AS company_name, c.type AS company_type FROM users u LEFT JOIN companies c ON c.id=u.company_id WHERE u.id=? LIMIT 1');
    $stmt->execute([$sessionUserId]);
    $cached = $stmt->fetch();
    if ($cached && empty($cached['company_id'])) {
        $resolvedCompanyId = resolve_company_id_for_user($cached);
        if ($resolvedCompanyId > 0) {
            $stmt->execute([$sessionUserId]);
            $cached = $stmt->fetch();
        }
    }
    $cachedUserId = $sessionUserId;
    if (!$cached) {
        unset($_SESSION['user_id']);
        $cachedUserId = 0;
        return $cached = null;
    }
    // last_seen é telemetria; se o SQLite estiver ocupado por milissegundos,
    // não deve derrubar uma página válida com HTTP 500.
    try {
        db()->prepare('UPDATE users SET last_seen=?, last_ip=? WHERE id=?')->execute([now(), isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', $cached['id']]);
    } catch (Throwable $ignored) {}
    return $cached;
}

function remember_cookie_name(): string { return 'linkexpress_remember'; }

function remember_cookie_secure(): bool {
    return !empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off';
}

function set_remember_cookie(string $value, int $expiresAt): void {
    setcookie(remember_cookie_name(), $value, [
        'expires'=>$expiresAt,
        'path'=>'/',
        'secure'=>remember_cookie_secure(),
        'httponly'=>true,
        'samesite'=>'Lax',
    ]);
    if($expiresAt>time())$_COOKIE[remember_cookie_name()]=$value;else unset($_COOKIE[remember_cookie_name()]);
}

function forget_remembered_login(): void {
    $cookie=(string)($_COOKIE[remember_cookie_name()]??'');
    $parts=strpos($cookie,':')!==false?explode(':',$cookie,2):[];
    $selector=(string)($parts[0]??'');
    if($selector!==''){
        try{db()->prepare('DELETE FROM remember_tokens WHERE selector=?')->execute([$selector]);}catch(Throwable $ignored){}
    }
    set_remember_cookie('',time()-3600);
}

function create_remembered_login(int $userId): void {
    if($userId<1)return;
    forget_remembered_login();
    $selector=bin2hex(random_bytes(12));$validator=bin2hex(random_bytes(32));$expires=time()+60*60*24*30;
    db()->prepare('INSERT INTO remember_tokens(user_id,selector,token_hash,expires_at,user_agent,created_at,last_used_at) VALUES(?,?,?,?,?,?,?)')
      ->execute([$userId,$selector,hash('sha256',$validator),date('Y-m-d H:i:s',$expires),substr((string)($_SERVER['HTTP_USER_AGENT']??''),0,500),now(),now()]);
    set_remember_cookie($selector.':'.$validator,$expires);
}

function restore_remembered_login(): bool {
    if(!empty($_SESSION['user_id']))return true;
    $cookie=(string)($_COOKIE[remember_cookie_name()]??'');
    if(!preg_match('/^([a-f0-9]{24}):([a-f0-9]{64})$/',$cookie,$m))return false;
    try{
        $q=db()->prepare("SELECT rt.*,u.status,u.blacklisted FROM remember_tokens rt JOIN users u ON u.id=rt.user_id WHERE rt.selector=? AND datetime(rt.expires_at)>datetime('now','localtime') LIMIT 1");
        $q->execute([$m[1]]);$row=$q->fetch();
        if(!$row||!hash_equals((string)$row['token_hash'],hash('sha256',$m[2]))||($row['status']??'')!=='active'||!empty($row['blacklisted'])){
            forget_remembered_login();return false;
        }
        session_regenerate_id(true);$_SESSION['user_id']=(int)$row['user_id'];
        $validator=bin2hex(random_bytes(32));$expires=time()+60*60*24*30;
        db()->prepare('UPDATE remember_tokens SET token_hash=?,expires_at=?,last_used_at=? WHERE id=?')->execute([hash('sha256',$validator),date('Y-m-d H:i:s',$expires),now(),$row['id']]);
        set_remember_cookie($m[1].':'.$validator,$expires);
        return true;
    }catch(Throwable $ignored){return false;}
}

function login_user($email, $password, $remember = false) {
    $stmt = db()->prepare('SELECT * FROM users WHERE lower(email)=lower(?) LIMIT 1');
    $stmt->execute([$email]);
    $user = $stmt->fetch();
    if (!$user || !password_verify($password, $user['password_hash'])) return false;
    if (!empty($user['blacklisted'])) return 'blacklisted';
    if ($user['status'] !== 'active') return 'inactive';
    session_regenerate_id(true);
    $_SESSION['user_id'] = $user['id'];
    if($remember)create_remembered_login((int)$user['id']);else forget_remembered_login();
    // A autenticação já foi concluída. Falha temporária ao registrar presença
    // ou histórico não pode deixar a sessão criada e mostrar erro 500.
    try {
        db()->prepare("UPDATE users SET last_seen=?, last_ip=?, work_status=CASE WHEN work_status='offline' THEN 'available' ELSE work_status END WHERE id=?")
            ->execute([now(), isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '', $user['id']]);
    } catch (Throwable $ignored) {}
    try { log_activity('login', 'users', $user['id'], 'Login realizado'); } catch (Throwable $ignored) {}
    return true;
}

function logout_user() {
    $u = current_user();
    if ($u) db()->prepare('UPDATE users SET work_status="offline", last_seen=? WHERE id=?')->execute([now(), $u['id']]);
    forget_remembered_login();
    $_SESSION = [];
    if (ini_get('session.use_cookies')) {
        $params = session_get_cookie_params();
        setcookie(session_name(), '', time() - 42000, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
    }
    session_destroy();
}

function require_auth() {
    if (!current_user()) redirect('login.php');
}

function require_roles($roles) {
    require_auth();
    $roles = (array)$roles;
    $role = (string)(current_user()['role'] ?? '');
    // O Sub Admin herda as áreas administrativas, mas as ações sensíveis
    // contra outros administradores são bloqueadas no backend.
    $allowed = in_array($role, $roles, true) || ($role === 'sub_admin' && in_array('super_admin', $roles, true));
    if (!$allowed) {
        http_response_code(403);
        exit('Você não tem permissão para acessar esta área.');
    }
}

function is_super_admin() { return current_user() && current_user()['role'] === 'super_admin'; }
function is_admin() { return current_user() && in_array(current_user()['role'], ['super_admin','sub_admin'], true); }
function is_role($roles) { return current_user() && in_array(current_user()['role'], (array)$roles, true); }
