#pragma once

#include <cstdint>
#include <functional>
#include <iosfwd>
#include <optional>
#include <span>

#include <sys/types.h>

namespace gamescope::Process
{
    void BecomeSubreaper();
    void SetDeathSignal( int nSignal );

    // Matches against comm, which the kernel truncates to 15 chars.
    bool IsProcessRunning( const char *pszComm );

    void KillAllChildren( pid_t nParentPid, int nSignal );
    void KillProcess( pid_t nPid, int nSignal );

    std::optional<int> WaitForChild( pid_t nPid );

    // Wait for all children to die,
    // but stop waiting if we hit a specific PID specified by onStopPid.
    // Returns true if we stopped because we hit the pid specified by onStopPid.
    //
    // Similar to what an `init` process would do.
    bool WaitForAllChildren( std::optional<pid_t> onStopPid = std::nullopt );

    bool CloseFd( int nFd );

    void RaiseFdLimit();
    void RestoreFdLimit();
    void ResetSignals();

    void CloseAllFds( std::span<int> nExcludedFds );

    void RemoveSteamOverlayFromPreload();

    // Stashes the LD_PRELOAD we were launched with so a child that can draw the overlay
    // gets handed it instead. Does nothing if we have no overlay or have already done this.
    void RestartWithoutSteamOverlay( char **argv );

    // Puts a stashed Steam overlay back into LD_PRELOAD for our children to inherit.
    // Returns whether there was anything stashed to put back.
    bool RestoreSteamOverlayPreload();

    pid_t SpawnProcess( char **argv, std::function<void()> fnPreambleInChild = nullptr, bool bDoubleFork = false );
    pid_t SpawnProcessInWatchdog( char **argv, bool bRespawn = false, std::function<void()> fnPreambleInChild = nullptr );

    bool HasCapSysNice();
    void SetNice( int nNice );
    void RestoreNice();

    bool SetRealtime();
    void RestoreRealtime();

    const char *GetProcessName();

    uint32_t GetAppIdFromCgroup( std::istream &stream );
    uint32_t GetAppIdFromReaper( pid_t pid );
    uint32_t GetAppIdFromPid( pid_t pid );
}
