#define _GNU_SOURCE
#include "ipc.h"
#include "logging.h"
#include "seccomp.h"

#include <errno.h>
#include <poll.h>
#include <seccomp.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

static void run_supervisor(pid_t child_pid, int err_pipe_fd, int notify_pipe_fd) {
    struct pollfd fds[2];
    int status;
    int running = 1;

    // Monitor seccomp traps
    fds[0].fd = err_pipe_fd;
    fds[0].events = POLLIN;

    // Monitor incoming IPC requests
    fds[1].fd = notify_pipe_fd;
    fds[1].events = POLLIN;

    while (running) {
        int ret = poll(fds, 2, -1);
        if (ret < 0) {
            if (errno == EINTR) continue;
            break;
        }

        // Polling seccomp policy violations
        if (fds[0].revents & POLLIN) {
            int syscall_num;
            if (read(fds[0].fd, &syscall_num, sizeof(int)) == sizeof(int)) {
                print_seccomp_violation(syscall_num);
            }
            running = 0; // Fail-secure
        } else if (fds[0].revents & POLLHUP) {
            running = 0; // Disconnect
        }

        // Polling IPC notifications
        if (fds[1].revents & POLLIN) {
            char dummy;
            if (read(fds[1].fd, &dummy, 1) == 1) {
                if (g_shm_mailbox->is_ready) {
                    handle_ipc_command(&g_shm_mailbox->message);
                    
                    // Release mailbox lock for subsequent operations
                    g_shm_mailbox->is_ready = 0; 
                }
            }
        }
    }

    waitpid(child_pid, &status, 0);
    
    // Forward the sandbox exit code
    if (WIFEXITED(status)) {
        _exit(WEXITSTATUS(status));
    } else {
        _exit(EXIT_FAILURE);
    }
}

void __attribute__((constructor)) init_sandbox(void) {
    // Prevent recursion in case of subsequent forks
    if (getenv("SANDBOX_ACTIVE")) return;

    setvbuf(stdout, NULL, _IONBF, 0);
    setvbuf(stderr, NULL, _IONBF, 0);
    
    // Setup IPC channel
    setup_ipc();

    // Setup signaling channels
    int pipe_err[2], pipe_notify[2];
    if (pipe(pipe_err) == -1 || pipe(pipe_notify) == -1) {
        LOG_CRIT("Failed to initialize signaling pipes");
        _exit(EXIT_FAILURE);
    }

    pid_t pid = fork();
    if (pid < 0) {
        LOG_CRIT("Failed to fork");
        _exit(EXIT_FAILURE);
    }

    if (pid == 0) {
        // Sandboxed process execution
        setenv("SANDBOX_ACTIVE", "1", 1);
        
        close(pipe_err[0]);
        close(pipe_notify[0]);
        
        g_ipc_notify_pipe = pipe_notify[1];
        g_error_pipe = pipe_err[1];

        // Setup SECCOMP rules
        setup_seccomp();

        return; 
    } else {
        // Supervisor Execution
        close(pipe_err[1]);
        close(pipe_notify[1]);
        
        run_supervisor(pid, pipe_err[0], pipe_notify[0]);
        
        __builtin_unreachable();
    }
}
