#ifndef SYSINFO_H
#define SYSINFO_H

#include <stdint.h>
#include <stddef.h>
#include <stdlib.h>

#include "tpm.h"    
#include "kernver.h"
#include "hex_utils.h"

const char *KERNVER_TYPE = "N/A. This is an error, please report at https://github.com/kxtzownsu/KVS with a picture of the screen.";


const char* getFirmwareVersion(){
    // note, may not work on all chromebooks
    // I also don't wanna have to rely on the crossystem binary for it

    // i hate ChromeOS
    FILE *fp;
    #ifdef __x86_64__
        char stupidfile[] = "/sys/class/platform/chromeos_acpi/FWID";
    #elif defined(__aarch64__)
        char stupidfile[] = "/proc/device-tree/firmware/chromeos/firmware-version";
    #elif defined(__arm__)
        char stupidfile[] = "/proc/device-tree/firmware/chromeos/firmware-version";
    #endif
    fp = fopen(stupidfile, "r");
    static char firmwareVersion[1024];

    if (fp == NULL) {
        printf("Error reading Firmware Version\n");
        printf("Please report as a bug at https://github.com/kxtzownsu/KVS\n");

        sleep(86400);
        return "Error!"; 
    }
    fgets(firmwareVersion, 100, fp);
    fclose(fp);
    trim_newline(firmwareVersion);

    return firmwareVersion;
}

const char* getTpmVersion(){
    char cmd[] = "tpmc tpmver";
    static char output[5];
    FILE* fp = popen(cmd, "r");
    fgets(output, sizeof(output), fp);
	fclose(fp);
    trim_newline(output);

    return output;
}

char* getKernver() {
    char cmd[] = "tpmc read 0x1008 9 2>/dev/null";
    static char output[26];
    FILE* fp = popen(cmd, "r");
    if (fgets(output, sizeof(output), fp) == NULL) {
        printf("Error reading kernver\n");
        printf("Please report as a bug at https://github.com/kxtzownsu/KVS\n");

        sleep(86400);
        return "Error!";
    }
	fclose(fp);
    trim_newline(output);
    
    uint32_t kernver = 0;
    static char kernver_str[18] = "0x00000000";

    // ewwww yucky i hate this
    // bitshift stuff sucks so bad when looking at it

    if (strncmp(output, "10", 2) == 0) {
        printf("using v1.0\n");
        unsigned int b1, b2, b3, b4;
        sscanf(output + 12, "%2x %2x %2x %2x", &b1, &b2, &b3, &b4);
        kernver = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
        snprintf(kernver_str, sizeof(kernver_str), "0x%08x (v1.0)", kernver);
        KERNVER_TYPE = "v1";
    } else if (strncmp(output, "2", 1) == 0) {
        unsigned int b1, b2, b3, b4;
        sscanf(output + 14, "%2x %2x %2x %2x", &b1, &b2, &b3, &b4);
        kernver = b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
        snprintf(kernver_str, sizeof(kernver_str), "0x%08x (v0.2)", kernver);
        KERNVER_TYPE = "v0";
    }

    KERNVER_TYPE = "v0";
    return kernver_str;
}

const char* getFWMPFlags(){
    char cmd[] = "tpmc read 0x100A 5 2>/dev/null";
    static char output[256];
    FILE* fp = popen(cmd, "r");
    fgets(output, sizeof(output), fp);
    fclose(fp);
    trim_newline(output);

    if (strcmp(output, "") == 0) {
        return "N/A (Most likely unenrolled)";
    }

    unsigned int fwmp = 0;
    int num_parsed = sscanf(output + 12, "%2x", &fwmp);
    static char fwmp_str[5];

    if (num_parsed != 1) {
        return "Failed to parse FWMP value from output.";
    }

    snprintf(fwmp_str, sizeof(fwmp_str), "0x%02x", fwmp);
    return fwmp_str;
}

const char* getGSCRWVersion(){
    char cmd[] = "gsctool -a -f | tail -n 1 | awk '{printf $2}'";
    static char output[8];
    FILE* fp = popen(cmd, "r");
    if (fgets(output, sizeof(output), fp) == NULL) {
        printf("Error reading GSC(cr50/ti50) version\n");
        printf("Please report as a bug at https://github.com/kxtzownsu/KVS\n");

        sleep(86400);
        return "Error!";
    }
	fclose(fp);
    trim_newline(output);

    return output;
}

// this being at a pre-made directory instead of
// being in PATH or /bin is probably bad, but
// I don't really care that much
const char* getGSCType(){
    char cmd[] = "/opt/kvs/bin/is_ti50 2>/dev/null";
    static char output[7];
    FILE* fp = popen(cmd, "r");
    if (fgets(output, sizeof(output), fp) == NULL) {
        printf("Error getting GSC(cr50/ti50) type!\n");
        printf("Please report as a bug at https://github.com/kxtzownsu/KVS\n");

        sleep(86400);
        return "Error!";
    }
	fclose(fp);
    trim_newline(output);

    return output;
}

#endif