import { exec, interval, Variable } from "astal";
import { Gtk } from "astal/gtk4";

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 = false;

const refreshStats = (): 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(refreshStats());

const availableFeatures = {
    cpu: true,
    ram: true,
};

const featureTest = () => {
    // Check if awk & sed are available
    try {
        exec("awk -V");
        exec("sed --version");
        enabled = true;
    } 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!",
        );
    }
};

const info = () => {
    return (
        <box vertical>
            <label
                label={"System Information"}
                cssClasses={["title-2"]}
            ></label>
            <Gtk.Separator marginTop={5} marginBottom={10}></Gtk.Separator>
            <label
                vexpand
                halign={Gtk.Align.START}
                hexpand
                label={ramUsed(used => {
                    return "RAM: " + used + ` (${ramUtil.get()}%)`;
                })}
            ></label>
            <label
                label={systemStats(stats => {
                    return `CPU: ${stats.cpuTemp}, ${stats.cpuClk}
GPU: ${stats.gpuTemp}, ${stats.gpuClk} (${stats.vram} / ${stats.availableVRAM})
Kernel: ${stats.kernel}`;
                })}
            ></label>
            <Gtk.Separator marginTop={10}></Gtk.Separator>
            <button
                onClicked={() => exec( `/bin/sh -c "kitty --hold fish -c 'fastfetch'"` )}
                child={
                    <label label={"View FastFetch"}></label>
                }></button>
        </box>
    );
};

const SystemInformationPanel = () => {
    const popover = new Gtk.Popover();

    popover.set_child(info());

    return popover;
};

const sysInfoFetcher = () => {
    if (enabled) {
        if (availableFeatures.cpu) {
            cpuUtil.set(
                "" +
                    Math.round(
                        parseFloat(exec(`/bin/fish -c cpu-utilization`)),
                    ),
            );
        }
        if (availableFeatures.ram) {
            ramUtil.set(
                "" +
                    Math.round(
                        parseFloat(
                            exec(
                                `/bin/bash -c "free | awk '/Mem/ { printf(\\"%.2f\\\\n\\", ($3/$2)*100) }'"`,
                            ),
                        ),
                    ),
            );
            ramUsed.set(
                exec(
                    `/bin/bash -c \"free -h | awk '/^Mem:/ {print $3 \\" used of \\" $2}'\"`,
                )
                    .replaceAll("Gi", "GiB")
                    .replaceAll("Mi", "MiB"),
            );
        }
        gpuUtil.set(exec("cat /sys/class/drm/card1/device/gpu_busy_percent"));
    }
};

const panel = SystemInformationPanel();

const SystemInfo = () => {
    featureTest();

    const openSysInfo = async () => {
        panel.popup();
        systemStats.set(refreshStats());
    };

    if (enabled) {
        sysInfoFetcher();
        interval(FETCH_INTERVAL, sysInfoFetcher);

        return (
            <button
                onClicked={() => openSysInfo()}
                child={
                    <box tooltipText={ramUsed(v => v)}>
                        <image
                            iconName={"power-profile-performance-symbolic"}
                            marginEnd={1}
                        ></image>
                        <label
                            label={cpuUtil(util => util)}
                            marginEnd={5}
                        ></label>
                        <image iconName={"histogram-symbolic"}></image>
                        <label label={ramUtil(util => util)}></label>
                        <image iconName={"show-gpu-effects-symbolic"}></image>
                        <label label={gpuUtil(util => util)}></label>
                        {panel}
                    </box>
                }
                cssClasses={["bar-button"]}
            ></button>
        );
    } else {
        return <image iconName={"action-unavailable-symbolic"}></image>;
    }
};

export default {
    SystemInfo,
    panel,
};
