/* Minimal C detector core for luci-app-hnsmmg2 (clean version) */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <sys/stat.h>
#include <unistd.h>

typedef struct {
    char* path;
    int line;
    char* line_text;
    char* token;
} Hit;

static Hit* hits = NULL;
static size_t hits_cap = 0;
static size_t hits_count = 0;

static void ensure_cap(size_t needed) {
    if (needed <= hits_cap) return;
    size_t new_cap = hits_cap ? hits_cap * 2 : 16;
    while (new_cap < needed) new_cap *= 2;
    Hit* tmp = realloc(hits, new_cap * sizeof(Hit));
    if (!tmp) return;
    hits = tmp;
    hits_cap = new_cap;
}

static void add_hit(const char* path, int line, const char* line_text, const char* token) {
    ensure_cap(hits_count + 1);
    Hit* h = &hits[hits_count++];
    h->path = strdup(path);
    h->line = line;
    h->line_text = strdup(line_text);
    h->token = strdup(token);
}

static int is_text_file(const char* path) {
    FILE* f = fopen(path, "rb");
    if (!f) return 0;
    unsigned char buf[4096];
    size_t n = fread(buf, 1, sizeof(buf), f);
    fclose(f);
    if (n == 0) return 0;
    for (size_t i = 0; i < n; i++) {
        if (buf[i] == 0) return 0;
    }
    return 1;
}

static void scan_file(const char* path) {
    if (!is_text_file(path)) return;
    FILE* f = fopen(path, "r");
    if (!f) return;
    char line[8192];
    int line_no = 0;
    // Simple pattern matching
    static const struct {
        const char* token;
        const char* label;
    } patterns[] = {
        { "TODO", "TODO" },
        { "FIXME", "FIXME" },
        { "system(", "system(" },
        { "popen(", "popen(" },
        { "exec(", "exec(" },
        { "fork(", "fork(" },
        { "strcpy(", "strcpy(" },
        { "memcpy(", "memcpy(" },
        { "strcat(", "strcat(" },
        { NULL, NULL }
    };
    while (fgets(line, sizeof(line), f)) {
        line_no++;
        for (size_t i = 0; patterns[i].token != NULL; i++) {
            if (strstr(line, patterns[i].token) != NULL) {
                add_hit(path, line_no, line, patterns[i].token);
                break;
            }
        }
    }
    fclose(f);
}

static void scan_dir(const char* dirpath) {
    DIR* d = opendir(dirpath);
    if (!d) return;
    struct dirent* ent;
    while ((ent = readdir(d)) != NULL) {
        if (strcmp(ent->d_name, ".") == 0 || strcmp(ent->d_name, "..") == 0) continue;
        char pathbuf[4096];
        snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dirpath, ent->d_name);
        struct stat st;
        if (stat(pathbuf, &st) == -1) continue;
        if (S_ISDIR(st.st_mode)) {
            scan_dir(pathbuf);
        } else if (S_ISREG(st.st_mode)) {
            scan_file(pathbuf);
        }
    }
    closedir(d);
}

int main(int argc, char** argv) {
    const char* root = ".";
    if (argc > 1) root = argv[1];
    scan_dir(root);
    // Output JSON array of hits
    printf("{\"root\":\"%s\",\"hits\":[", root);
    for (size_t i = 0; i < hits_count; i++) {
        if (i) printf(",");
        printf("{\"path\":\"%s\",\"line\":%d,\"token\":\"%s\",\"line_text\":\"", hits[i].path, hits[i].line, hits[i].token);
        const char* s = hits[i].line_text;
        for (size_t j = 0; s[j] != '\0'; j++) {
            unsigned char c = s[j];
            if (c == '"') printf("\\\"");
            else if (c == '\\') printf("\\\\");
            else if (c == '\n') printf("\\n");
            else if (c == '\r') printf("\\r");
            else printf("%c", c);
        }
        printf(""}\n");
    }
    printf("]}");
    // free resources
    for (size_t i = 0; i < hits_count; i++) {
        free(hits[i].path);
        free(hits[i].line_text);
        free(hits[i].token);
    }
    free(hits);
    return 0;
}
