#include "launcher.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <fcntl.h>

/* ── SIGCHLD handler ──────────────────────────────────────────────────────── */

int launcher_reap_children(void)
{
    int count = 0;
    int status;
    pid_t pid;
    while ((pid = waitpid(-1, &status, WNOHANG)) > 0)
        count++;
    return count;
}

static void sigchld_handler(int sig)
{
    (void)sig;
    launcher_reap_children();
}

void launcher_install_sigchld(void)
{
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_handler = sigchld_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
    sigaction(SIGCHLD, &sa, NULL);
}

/* ── launch ───────────────────────────────────────────────────────────────── */

pid_t launcher_launch(const DesktopEntry *entry)
{
    if (!entry || !entry->exec[0]) return -1;

    /* Build command:
       - terminal apps: prepend "x-terminal-emulator -e "
       - others: run directly via sh -c */
    char cmd[1024];
    if (entry->terminal) {
        /* Wrap in a terminal emulator; x-terminal-emulator is a Debian/Ubuntu
           alternatives symlink; xterm is the universal fallback */
        snprintf(cmd, sizeof(cmd), "x-terminal-emulator -e %s", entry->exec);
    } else {
        snprintf(cmd, sizeof(cmd), "%s", entry->exec);
    }

    pid_t pid = fork();
    if (pid < 0) {
        perror("fork");
        return -1;
    }

    if (pid == 0) {
        /* Child: double-fork so we don't need to wait */
        pid_t grandchild = fork();
        if (grandchild < 0) {
            perror("fork (grandchild)");
            _exit(1);
        }
        if (grandchild == 0) {
            /* Grandchild: detach from any session, exec the app */
            setsid();

            /* Close fd 0/1/2 and reopen as /dev/null to avoid blocking on wm */
            int devnull = open("/dev/null", 0);
            if (devnull >= 0) {
                dup2(devnull, 0);
                dup2(devnull, 1);
                dup2(devnull, 2);
                if (devnull > 2) close(devnull);
            }

            execl("/bin/sh", "sh", "-c", cmd, (char *)NULL);
            _exit(127);
        }
        /* First child exits immediately so parent waitpid() cleans it up */
        _exit(0);
    }

    /* Parent: reap the first child */
    int status;
    waitpid(pid, &status, 0);

    return pid; /* not very useful after double-fork, but signals success */
}