import { exec, execAsync, interval, Variable } from "astal";

const FETCH_INTERVAL = 2000;
const cpuUtil = Variable("0%");
const ramUtil = Variable("0%");
const ramUsed = Variable("0MiB");
const gpuUtil = Variable("0%");
let gpuName = "card1";
let enabled = true;

const getStats = (): Stats => {
    gpuName = exec(`/bin/bash -c "ls /sys/class/drm/ | grep '^card[0-9]*$'"`);
    const cpuNameInSensors = "CPUTIN";
    const stats = {
        kernel: exec("uname -sr"),
        cpuTemp: exec(
            `/bin/bash -c "sensors | grep -m1 ${cpuNameInSensors} | awk '{print $2}'"`,
        ),
        cpuClk: exec(
            `awk '/cpu MHz/ {sum+=$4; ++n} END {print sum/n " MHz"}' /proc/cpuinfo`,
        ),
        gpuTemp: exec(
            `/bin/bash -c "sensors | grep -E 'edge' | awk '{print $2}'"`,
        ),
        gpuClk: exec(
            `/bin/bash -c "cat /sys/class/drm/${gpuName}/device/pp_dpm_sclk | grep '\\*' | awk '{print $2 $3}'"`,
        ),
        vram:
            Math.round(
                parseInt(
                    exec(
                        `cat /sys/class/drm/${gpuName}/device/mem_info_vram_used`,
                    ),
                ) /
                1024 /
                1024,
            ) + "MiB",
        availableVRAM:
            Math.round(
                parseInt(
                    exec(
                        `cat /sys/class/drm/${gpuName}/device/mem_info_vram_total`,
                    ),
                ) /
                1024 /
                1024,
            ) + "MiB",
    };

    return stats;
};

const systemStats: Variable<Stats> = Variable(getStats());
const availableFeatures = {
    cpu: true,
    ram: true,
};

const refreshStats = () => {
    systemStats.set(getStats());
}

const featureTest = () => {
    print('[SysInfo] Feature test started...');
    // Check if awk & sed are available
    try {
        exec("awk -V");
        exec("sed --version");
    } catch (e) {
        printerr(
            "[ SysInfo ] AWK or SED missing! No system info will be available",
        );
        enabled = false;
        return;
    }

    // Check if mpstat is available
    try {
        exec("mpstat -V");
    } catch (e) {
        availableFeatures.cpu = false;
        printerr(
            "[ SysInfo ] Feature Test for CPU info failed. mpstat from the sysstat package missing!",
        );
    }
    print('[SysInfo] Feature test complete');
};

const sysInfoFetcher = () => {
    if (enabled) {
        if (availableFeatures.cpu) {
            execAsync(`/bin/fish -c cpu-utilization`).then(v => {
                cpuUtil.set("" + Math.round(parseFloat(v)));
            }).catch(e => {
                console.error(e);
            });
        }
        if (availableFeatures.ram) {
            execAsync(
                `/bin/bash -c "free | awk '/Mem:/ {print $3 \\" \\" $2}'"`,
            ).then(v => {
                const util = parseInt(v.split(' ')[0]);
                const available = parseInt(v.split(' ')[1]);
                ramUtil.set("" + Math.round(util / available * 100));
                ramUsed.set(`${Math.round(util / 1024 / 1024 * 10) / 10} GiB of ${Math.round(available / 1024 / 1024 * 10) / 10} GiB used`);
            }).catch(e => {
                console.error(e);
            });
        }
        gpuUtil.set(exec("cat /sys/class/drm/card1/device/gpu_busy_percent"));
    }
};

let sysInfoFetcherRunning = false;
const startSysInfoFetcher = () => {
    if (!sysInfoFetcherRunning) {
        sysInfoFetcherRunning = true;

        featureTest();

        if (enabled) {
            // Start interval
            interval(FETCH_INTERVAL, sysInfoFetcher);
        }
    }
}

export default {
    startSysInfoFetcher,
    enabled,
    gpuUtil,
    cpuUtil,
    ramUsed,
    ramUtil,
    refreshStats,
    systemStats
}
