#include "static_file_api.h"
#include "esp_log.h"
#include <fcntl.h>
#include <string.h>
#include "esp_vfs.h"

static const char *TAG = "static_file_api";

#define FILE_PATH_MAX (ESP_VFS_PATH_MAX + 128)
#define SCRATCH_BUFSIZE (10240)

typedef struct rest_server_context {
    char base_path[ESP_VFS_PATH_MAX + 1];
    char scratch[SCRATCH_BUFSIZE];
} rest_server_context_t;

#define CHECK_FILE_EXTENSION(filename, ext) \
    (strcasecmp(&filename[strlen(filename) - strlen(ext)], ext) == 0)

static esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filepath) {
    const char *type = "text/plain";
    if (CHECK_FILE_EXTENSION(filepath, ".html")) type = "text/html";
    else if (CHECK_FILE_EXTENSION(filepath, ".js")) type = "application/javascript";
    else if (CHECK_FILE_EXTENSION(filepath, ".css")) type = "text/css";
    else if (CHECK_FILE_EXTENSION(filepath, ".png")) type = "image/png";
    else if (CHECK_FILE_EXTENSION(filepath, ".ico")) type = "image/x-icon";
    else if (CHECK_FILE_EXTENSION(filepath, ".svg")) type = "image/svg+xml";
    return httpd_resp_set_type(req, type);
}

static esp_err_t static_get_handler(httpd_req_t *req) {
    char filepath[FILE_PATH_MAX];
    rest_server_context_t *ctx = (rest_server_context_t *) req->user_ctx;

    strlcpy(filepath, ctx->base_path, sizeof(filepath));
    if (req->uri[strlen(req->uri) - 1] == '/') {
        strlcat(filepath, "/index.html", sizeof(filepath));
    } else {
        strlcat(filepath, req->uri, sizeof(filepath));
    }

    int fd = open(filepath, O_RDONLY, 0);
    if (fd == -1) {
        // fallback para /index.html (SPA)
        ESP_LOGW(TAG, "Arquivo não encontrado: %s. Tentando index.html", filepath);
        strlcpy(filepath, ctx->base_path, sizeof(filepath));
        strlcat(filepath, "/index.html", sizeof(filepath));
        fd = open(filepath, O_RDONLY, 0);
        if (fd == -1) {
            httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Arquivo não encontrado");
            return ESP_FAIL;
        }
    }

    set_content_type_from_file(req, filepath);

    char *chunk = ctx->scratch;
    ssize_t read_bytes;
    do {
        read_bytes = read(fd, chunk, SCRATCH_BUFSIZE);
        if (read_bytes == -1) {
            ESP_LOGE(TAG, "Erro lendo arquivo: %s", filepath);
            close(fd);
            httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao ler arquivo");
            return ESP_FAIL;
        } else if (read_bytes > 0) {
            if (httpd_resp_send_chunk(req, chunk, read_bytes) != ESP_OK) {
                close(fd);
                httpd_resp_sendstr_chunk(req, NULL);
                httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Erro ao enviar arquivo");
                return ESP_FAIL;
            }
        }
    } while (read_bytes > 0);

    close(fd);
    httpd_resp_send_chunk(req, NULL, 0);
    return ESP_OK;
}

void register_static_file_handlers(httpd_handle_t server, void *ctx) {
    httpd_uri_t uri = {
        .uri = "/*",
        .method = HTTP_GET,
        .handler = static_get_handler,
        .user_ctx = ctx
    };
    httpd_register_uri_handler(server, &uri);
}
