#ifndef PROTOTYPE1_SRC_SYSTEM_FILEIO_H
#define PROTOTYPE1_SRC_SYSTEM_FILEIO_H

#include "../core/VecU8_as_str.h"

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>

typedef struct {
    Result_variant variant;
    union {
        VecU8 Ok;
        int Err;
    };
} Result_VecU8_or_int;

void Result_VecU8_or_int_drop(Result_VecU8_or_int obj) {
    if (obj.variant == Result_Ok)
        VecU8_drop(obj.Ok);
}

typedef struct {
    Result_variant variant;
    int Err;
} Result_ok_or_int;

void Result_ok_or_int_drop(Result_ok_or_int obj) {}

NODISCARD VecU8 read_whole_file_or_abort(SpanU8 path) {
    VecU8 filename = VecU8_fmt("%s%c", path, 0);
    FILE* fp = fopen((const char*)filename.buf, "rb");
    if (!fp)
        abortf("Can't open file %s: %s\n", (const char*)filename.buf, strerror(errno));
    VecU8_drop(filename);
    if (fseek(fp, 0, SEEK_END) != 0) {
        abortf("fseek: %s\n", strerror(errno));
    }
    long file_size = ftell(fp);
    if (file_size < 0) {
        abortf("ftell: %s\n", strerror(errno));
    }
    if (fseek(fp, 0, SEEK_SET) != 0) {
        abortf("fseek: %s\n", strerror(errno));
    }
    VecU8 result = (VecU8){.buf = safe_malloc(file_size), .len = file_size, .capacity = file_size};
    size_t nread = fread(result.buf, 1, (size_t)file_size, fp);
    if (nread < file_size) {
        abortf("fread\n");
    }
    fclose(fp);
    return result;
}

NODISCARD VecU8 read_file_by_path(VecU8 path){
    VecU8 content = read_whole_file_or_abort(VecU8_to_span(&path));
    VecU8_drop(path);
    return content;
}

void write_whole_file_or_abort(const char* filename, SpanU8 content) {
    FILE* fd = fopen(filename, "wb");
    if (!fd) {
        abortf("Can't open file %s: %s\n", filename, strerror(errno));
    }
    if (fwrite(content.data, 1, content.len, fd) < content.len) {
        abortf("fwrite\n");
    }
    fclose(fd);
}


#endif
