#include <zephyr/kernel.h>
#include <zephyr/device.h>
#include <zephyr/logging/log.h>
#include <zephyr/fs/fs.h>
#include <zephyr/storage/disk_access.h>
#include <zephyr/drivers/spi.h>
#include <zephyr/drivers/flash.h>

#define MX25R6435F_DEVICE_NAME "MX25R6435F"
#define DISK_MOUNT_PT "/" MX25R6435F_DEVICE_NAME ":"

static struct fs_mount_t mp = {
    .type = FS_FATFS, // Make sure to support FATFS
    .fs_data = NULL,  // Assuming no special data is required for the flash filesystem
};

LOG_MODULE_REGISTER(main);

#define MAX_PATH 128
#define FILE_NAME "testfile.txt"
#define SAMPLE_TEXT "Hello, Zephyr!\n"
#define APPEND_TEXT "Appending text.\n"

/* Function to create a text file */
static bool create_file(const char *file_path) {
    struct fs_file_t file;
    fs_file_t_init(&file);

    if (fs_open(&file, file_path, FS_O_CREATE | FS_O_RDWR) != 0) {
        LOG_ERR("Failed to create file %s", file_path);
        return false;
    }

    LOG_INF("File %s created", file_path);
    fs_close(&file);
    return true;
}

/* Function to write to a text file */
static bool write_to_file(const char *file_path, const char *text) {
    struct fs_file_t file;
    ssize_t bytes_written;
    fs_file_t_init(&file);

    if (fs_open(&file, file_path, FS_O_RDWR) != 0) {
        LOG_ERR("Failed to open file %s", file_path);
        return false;
    }

    bytes_written = fs_write(&file, text, strlen(text));
    if (bytes_written < 0) {
        LOG_ERR("Failed to write to file %s", file_path);
        fs_close(&file);
        return false;
    }

    LOG_INF("Wrote %d bytes to file %s", bytes_written, file_path);
    fs_close(&file);
    return true;
}

/* Function to read from a text file */
static bool read_from_file(const char *file_path, char *buffer, size_t buf_size) {
    struct fs_file_t file;
    ssize_t bytes_read;
    fs_file_t_init(&file);

    if (fs_open(&file, file_path, FS_O_READ) != 0) {
        LOG_ERR("Failed to open file %s", file_path);
        return false;
    }

    bytes_read = fs_read(&file, buffer, buf_size - 1);  // Leave space for null terminator
    if (bytes_read < 0) {
        LOG_ERR("Failed to read from file %s", file_path);
        fs_close(&file);
        return false;
    }

    buffer[bytes_read] = '\0';  // Null terminate the string
    LOG_INF("Read %d bytes from file %s", bytes_read, file_path);
    fs_close(&file);
    return true;
}

/* Function to append to a text file */
static bool append_to_file(const char *file_path, const char *text) {
    struct fs_file_t file;
    ssize_t bytes_written;
    fs_file_t_init(&file);

    if (fs_open(&file, file_path, FS_O_APPEND) != 0) {
        LOG_ERR("Failed to open file %s", file_path);
        return false;
    }

    bytes_written = fs_write(&file, text, strlen(text));
    if (bytes_written < 0) {
        LOG_ERR("Failed to append to file %s", file_path);
        fs_close(&file);
        return false;
    }

    LOG_INF("Appended %d bytes to file %s", bytes_written, file_path);
    fs_close(&file);
    return true;
}

/* Function to delete a text file */
static bool delete_file(const char *file_path) {
    int res = fs_unlink(file_path);
    if (res != 0) {
        LOG_ERR("Failed to delete file %s", file_path);
        return false;
    }

    LOG_INF("File %s deleted", file_path);
    return true;
}

int main(void) {
    char buffer[128];

    /* Initialize the flash and mount it */
    mp.mnt_point = DISK_MOUNT_PT;

    if (disk_access_init(MX25R6435F_DEVICE_NAME) != 0) {
        LOG_ERR("Storage init ERROR!");
        return -1;
    }

    if (fs_mount(&mp) != 0) {
        LOG_ERR("Error mounting disk.");
        return -1;
    }

    printk("Disk mounted.\n");

    /* Create the file */
    if (create_file(DISK_MOUNT_PT FILE_NAME)) {
        printk("File created.\n");
    }

    /* Write to the file */
    if (write_to_file(DISK_MOUNT_PT FILE_NAME, SAMPLE_TEXT)) {
        printk("Written to file: %s\n", SAMPLE_TEXT);
    }

    /* Read from the file */
    if (read_from_file(DISK_MOUNT_PT FILE_NAME, buffer, sizeof(buffer))) {
        printk("Read from file: %s\n", buffer);
    }

    /* Append to the file */
    if (append_to_file(DISK_MOUNT_PT FILE_NAME, APPEND_TEXT)) {
        printk("Appended to file: %s\n", APPEND_TEXT);
    }

    /* Read from the file again */
    if (read_from_file(DISK_MOUNT_PT FILE_NAME, buffer, sizeof(buffer))) {
        printk("Read after append: %s\n", buffer);
    }

    /* Delete the file */
    if (delete_file(DISK_MOUNT_PT FILE_NAME)) {
        printk("File deleted.\n");
    }

    /* Unmount the filesystem */
    fs_unmount(&mp);
    printk("Disk unmounted.\n");

    return 0;
}
