#include "audio.h"

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

/* ── state ───────────────────────────────────────────────────────────────── */

static pid_t  s_pid     = -1;       /* ffplay child PID, -1 = not running    */
static int    s_paused  = 0;
static int    s_volume  = 80;       /* 0-100                                 */
static char   s_file[1024] = {0};   /* currently loaded file path            */

/* ── internal helpers ────────────────────────────────────────────────────── */

/* Returns 1 if the child process is still alive */
static int child_alive(void)
{
    if (s_pid <= 0) return 0;
    /* waitpid with WNOHANG: returns 0 if still running */
    int status;
    pid_t r = waitpid(s_pid, &status, WNOHANG);
    if (r == 0) return 1;      /* still running                               */
    s_pid    = -1;             /* reaped or error → mark dead                 */
    s_paused = 0;
    return 0;
}

static void kill_child(void)
{
    if (!child_alive()) return;
    kill(s_pid, SIGTERM);
    /* Give it 100 ms to exit cleanly, then SIGKILL */
    usleep(100000);
    if (child_alive()) kill(s_pid, SIGKILL);
    /* Reap */
    int status;
    waitpid(s_pid, &status, 0);
    s_pid    = -1;
    s_paused = 0;
}

/* Spawn ffplay in the background, silenced, looping */
static int spawn_ffplay(const char *filepath, int volume)
{
    pid_t pid = fork();
    if (pid < 0) { perror("audio: fork"); return 0; }

    if (pid == 0) {
        /* ── child ── */
        /* Detach from terminal; redirect all output to /dev/null */
        int devnull = open("/dev/null", O_RDWR);
        if (devnull >= 0) {
            dup2(devnull, STDIN_FILENO);
            dup2(devnull, STDOUT_FILENO);
            dup2(devnull, STDERR_FILENO);
            if (devnull > 2) close(devnull);
        }
        setsid();

        /* ffplay flags:
           -nodisp        no video window
           -autoexit      (we set -loop so this is redundant but harmless)
           -loop 0        loop forever
           -volume <n>    0-100
           -loglevel quiet suppress console spam                              */
        char vol_str[8];
        snprintf(vol_str, sizeof(vol_str), "%d", volume);

        execlp("ffplay", "ffplay",
               "-nodisp",
               "-loop",    "0",
               "-volume",  vol_str,
               "-loglevel","quiet",
               filepath,
               (char *)NULL);
        /* exec failed */
        _exit(127);
    }

    /* ── parent ── */
    s_pid    = pid;
    s_paused = 0;
    return 1;
}

/* ── public API ──────────────────────────────────────────────────────────── */

void audio_init(void)
{
    /* nothing to do currently */
}

int audio_play(const char *filepath)
{
    if (!filepath || !filepath[0]) return 0;

    audio_stop();   /* kill any previous track */

    snprintf(s_file, sizeof(s_file), "%s", filepath);

    if (!spawn_ffplay(filepath, s_volume)) {
        fprintf(stderr, "audio: could not start ffplay for '%s'\n", filepath);
        return 0;
    }

    fprintf(stderr, "audio: playing '%s' (vol %d)\n", filepath, s_volume);
    return 1;
}

void audio_pause(void)
{
    if (!child_alive() || s_paused) return;
    kill(s_pid, SIGSTOP);
    s_paused = 1;
}

void audio_resume(void)
{
    if (!child_alive() || !s_paused) return;
    kill(s_pid, SIGCONT);
    s_paused = 0;
}

void audio_stop(void)
{
    kill_child();
    s_file[0] = '\0';
}

void audio_set_volume(int vol)
{
    if (vol < 0)   vol = 0;
    if (vol > 100) vol = 100;
    s_volume = vol;

    /* If already playing, restart at the new volume */
    if (child_alive() && s_file[0]) {
        char tmp[1024];
        snprintf(tmp, sizeof(tmp), "%s", s_file);
        audio_stop();
        spawn_ffplay(tmp, s_volume);
        snprintf(s_file, sizeof(s_file), "%s", tmp);
    }
}

int audio_is_playing(void)
{
    return child_alive() && !s_paused;
}

void audio_free(void)
{
    audio_stop();
}