#include "sd_manager.h"
#include <SD.h>
#include <SPI.h>

static File s_file;
static bool s_fileOpen = false;

static bool hasGcodeExtension(const char* name) {
    const char* dot = strrchr(name, '.');
    if (!dot) return false;
    // case-insensitive compare
    char ext[8] = {};
    for (int i = 0; i < 7 && dot[i + 1]; i++) {
        ext[i] = (char)tolower((unsigned char)dot[i + 1]);
    }
    return strcmp(ext, "gcode") == 0 || strcmp(ext, "nc") == 0;
}

bool sd_init() {
    return SD.begin(PIN_SD_CS);
}

uint8_t sd_list_files(char files[][FILENAME_MAX_LEN], uint8_t maxCount) {
    File root = SD.open("/");
    if (!root) return 0;

    uint8_t count = 0;
    while (count < maxCount) {
        File entry = root.openNextFile();
        if (!entry) break;
        if (!entry.isDirectory()) {
            const char* name = entry.name();
            if (hasGcodeExtension(name)) {
                strncpy(files[count], name, FILENAME_MAX_LEN - 1);
                files[count][FILENAME_MAX_LEN - 1] = '\0';
                count++;
            }
        }
        entry.close();
    }
    root.close();
    return count;
}

bool sd_open_file(const char* filename) {
    if (s_fileOpen) sd_close_file();

    // Build full path
    char path[FILENAME_MAX_LEN + 2];
    snprintf(path, sizeof(path), "/%s", filename);

    s_file = SD.open(path, FILE_READ);
    s_fileOpen = (bool)s_file;
    return s_fileOpen;
}

uint32_t sd_count_lines() {
    if (!s_fileOpen) return 0;
    s_file.seek(0);
    uint32_t lines = 0;
    while (s_file.available()) {
        char c = (char)s_file.read();
        if (c == '\n') lines++;
    }
    // Count last line if file doesn't end with newline
    if (s_file.size() > 0) {
        s_file.seek(s_file.size() - 1);
        char last = (char)s_file.read();
        if (last != '\n') lines++;
    }
    s_file.seek(0);
    return lines;
}

bool sd_read_line(char* buf, uint16_t bufLen) {
    if (!s_fileOpen || !s_file.available()) return false;
    uint16_t n = s_file.readBytesUntil('\n', buf, bufLen - 1);
    buf[n] = '\0';
    // Strip carriage return
    if (n > 0 && buf[n - 1] == '\r') buf[n - 1] = '\0';
    return true;
}

void sd_close_file() {
    if (s_fileOpen) {
        s_file.close();
        s_fileOpen = false;
    }
}

bool sd_is_file_open() {
    return s_fileOpen;
}
