#ifndef SISC_MANUAL_DINAMICO_H
#define SISC_MANUAL_DINAMICO_H

#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <sys/stat.h>

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

static uint64_t md_fnv1a_arquivo(const char *path, int *ok, off_t *size_out, time_t *mtime_out)
{
    if (ok) *ok = 0;
    if (size_out) *size_out = 0;
    if (mtime_out) *mtime_out = 0;
    struct stat st;
    if (!path || stat(path, &st) != 0 || !S_ISREG(st.st_mode)) return 0;
    if (size_out) *size_out = st.st_size;
    if (mtime_out) *mtime_out = st.st_mtime;
    FILE *f = fopen(path, "rb");
    if (!f) return 0;
    uint64_t h = 1469598103934665603ULL;
    unsigned char buf[8192];
    size_t n;
    while ((n = fread(buf, 1, sizeof(buf), f)) > 0) {
        for (size_t i = 0; i < n; i++) { h ^= (uint64_t)buf[i]; h *= 1099511628211ULL; }
    }
    int erro = ferror(f);
    fclose(f);
    if (erro) return 0;
    if (ok) *ok = 1;
    return h;
}

static void md_iso_mtime(time_t t, char out[32])
{
    if (!t) { snprintf(out, 32, "ausente"); return; }
    struct tm tmv;
    gmtime_r(&t, &tmv);
    strftime(out, 32, "%Y-%m-%dT%H:%M:%SZ", &tmv);
}

static void md_assinatura_path(const char *path, char *out, size_t outsz)
{
    int ok = 0; off_t sz = 0; time_t mt = 0;
    uint64_t h = md_fnv1a_arquivo(path, &ok, &sz, &mt);
    if (!ok) { snprintf(out, outsz, "ausente"); return; }
    char mtiso[32]; md_iso_mtime(mt, mtiso);
    snprintf(out, outsz, "ok size=%lld mtime=%s fnv=%016llx", (long long)sz, mtiso, (unsigned long long)h);
}

static char *md_ler_arquivo_limite(const char *path, size_t max_bytes, size_t *len_out)
{
    if (len_out) *len_out = 0;
    FILE *f = fopen(path, "rb");
    if (!f) return NULL;
    char *buf = malloc(max_bytes + 1);
    if (!buf) { fclose(f); return NULL; }
    size_t n = fread(buf, 1, max_bytes, f);
    fclose(f);
    buf[n] = '\0';
    if (len_out) *len_out = n;
    return buf;
}

static void md_compactar_texto(const char *in, char *out, size_t outsz)
{
    if (!out || outsz == 0) return;
    size_t j = 0; int esp = 0;
    for (const unsigned char *p = (const unsigned char *)(in ? in : ""); *p && j + 1 < outsz; p++) {
        unsigned char c = *p;
        if (c == '\\' && p[1] == 'n') { c = ' '; p++; }
        if (c == '\n' || c == '\r' || c == '\t' || c == ' ') {
            if (!esp && j > 0) out[j++] = ' ';
            esp = 1;
        } else if (c >= 32) {
            out[j++] = (char)c;
            esp = 0;
        }
    }
    while (j > 0 && out[j - 1] == ' ') j--;
    out[j] = '\0';
}

static int md_token_ja_existe(const char *lista, const char *tok)
{
    size_t n = strlen(tok);
    const char *p = lista;
    while ((p = strstr(p, tok)) != NULL) {
        int antes = (p == lista || p[-1] == ' ' || p[-1] == ',' || p[-1] == ';');
        int depois = (p[n] == '\0' || p[n] == ' ' || p[n] == ',' || p[n] == ';');
        if (antes && depois) return 1;
        p += n;
    }
    return 0;
}

static void md_add_token(char *out, size_t outsz, const char *tok)
{
    if (!tok || !*tok || md_token_ja_existe(out, tok)) return;
    size_t l = strlen(out), n = strlen(tok);
    if (l + n + 3 >= outsz) return;
    if (l) { strncat(out, ", ", outsz - strlen(out) - 1); }
    strncat(out, tok, outsz - strlen(out) - 1);
}

static int md_starts_with(const char *s, const char *pre)
{
    return s && pre && strncmp(s, pre, strlen(pre)) == 0;
}

static int md_ends_with(const char *s, const char *suf)
{
    if (!s || !suf) return 0;
    size_t ns = strlen(s), nf = strlen(suf);
    return ns >= nf && strcmp(s + ns - nf, suf) == 0;
}

static const char *md_basename_rel(const char *rel)
{
    const char *b = rel ? strrchr(rel, '/') : NULL;
    return b ? b + 1 : (rel ? rel : "");
}

static int md_rel_eh_contexto_sisc(const char *rel)
{
    if (!rel || !*rel) return 1;
    const char *base = md_basename_rel(rel);

    if (md_starts_with(rel, "rascunho/") || strstr(rel, "/rascunho/")) return 1;
    if (md_starts_with(rel, "secretos/") || strstr(rel, "/secretos/") || md_starts_with(rel, "core/biblioteca-secretos/")) return 1;
    if (md_starts_with(rel, "espaco/") || strstr(rel, "/espaco/")) return 1;
    if (md_starts_with(rel, "sessoes/") || strstr(rel, "/sessoes/")) return 1;

    /* Lei fonte-código: árvores e artefatos gerados são contexto de entendimento/uso,
     * não código de funcionamento. Exemplos: operador-manual-*.json e reversao-gc. */
    if (md_ends_with(rel, ".json") && (md_starts_with(rel, "arvores/") || strstr(rel, "/arvores/"))) return 1;
    if (!strncmp(base, "operador-manual-", 16) || !strcmp(base, "reversao-gc.json")) return 1;
    if (strstr(rel, "/public/") || md_starts_with(rel, "public/")) return 1;
    if (strstr(rel, "/avaliacoes/") || strstr(rel, "/avaliacoes-spec/") || strstr(rel, "/tarefas/")) return 1;
    return 0;
}

static int md_rel_eh_fonte_codigo_sisc(const char *rel)
{
    if (!rel || !*rel || md_rel_eh_contexto_sisc(rel)) return 0;

    if (!strcmp(rel, "pp.c") || !strcmp(rel, "Makefile") || !strcmp(rel, ".gitignore") || !strcmp(rel, ".ignorecontexto")) return 1;
    if (md_starts_with(rel, "core/") && !md_starts_with(rel, "core/biblioteca-secretos/") && !md_starts_with(rel, "core/biblioteca-contas-llm/")) return 1;
    if (md_starts_with(rel, "ajuda/")) return 1;

    if (strstr(rel, "/agentes/") || md_starts_with(rel, "agentes/")) return 1;
    if (strstr(rel, "/spec-diretivas/") || md_starts_with(rel, "spec-diretivas/")) return 1;
    if (strstr(rel, "/config/") || md_starts_with(rel, "config/")) return 1;
    if (strstr(rel, "/escuta/") || md_starts_with(rel, "escuta/")) return 1;
    if (strstr(rel, "/web-api/catalogo-mensagens.json") || md_starts_with(rel, "web-api/catalogo-mensagens.json")) return 1;
    if (strstr(rel, "/formatos-escuta/") || md_starts_with(rel, "formatos-escuta/")) return 1;
    if (strstr(rel, "/conectores/formatos/") || md_starts_with(rel, "conectores/formatos/")) return 1;
    if (strstr(rel, "/conectores/") || md_starts_with(rel, "conectores/")) return 1;

    if (md_ends_with(rel, ".c") || md_ends_with(rel, ".h") || md_ends_with(rel, ".php") ||
        md_ends_with(rel, ".sh") || md_ends_with(rel, ".py") || md_ends_with(rel, ".js") ||
        md_ends_with(rel, ".ts") || md_ends_with(rel, ".css")) return 1;
    return 0;
}

static void md_extrair_flags(const char *txt, char *out, size_t outsz)
{
    if (!out || outsz == 0) return;
    out[0] = '\0';
    const char *p = txt ? txt : "";
    while ((p = strstr(p, "--")) != NULL) {
        const char *q = p + 2;
        if (!isalpha((unsigned char)*q)) { p += 2; continue; }
        char tok[96]; size_t j = 0;
        tok[j++] = '-'; tok[j++] = '-';
        while ((*q == '-' || *q == '_' || isalnum((unsigned char)*q)) && j + 1 < sizeof(tok)) tok[j++] = *q++;
        if (*q == '=' || *q == ':') tok[j++] = *q;
        tok[j] = '\0';
        md_add_token(out, outsz, tok);
        p = q;
    }
    if (!out[0]) snprintf(out, outsz, "nenhuma flag -- detectada no trecho lido");
}

static void md_extrair_funcoes_c(const char *txt, char *out, size_t outsz)
{
    if (!out || outsz == 0) return;
    out[0] = '\0';
    const char *p = txt ? txt : "";
    if (strstr(p, "int main(")) md_add_token(out, outsz, "main");
    while ((p = strstr(p, "static ")) != NULL) {
        const char *abre = strchr(p, '(');
        const char *linha = strchr(p, '\n');
        if (abre && (!linha || abre < linha)) {
            const char *fim = abre;
            while (fim > p && isspace((unsigned char)fim[-1])) fim--;
            const char *ini = fim;
            while (ini > p && (isalnum((unsigned char)ini[-1]) || ini[-1] == '_')) ini--;
            if (fim > ini) {
                char nome[96]; size_t n = (size_t)(fim - ini);
                if (n >= sizeof(nome)) n = sizeof(nome) - 1;
                memcpy(nome, ini, n); nome[n] = '\0';
                if (strcmp(nome, "if") && strcmp(nome, "while") && strcmp(nome, "for") && strcmp(nome, "switch")) md_add_token(out, outsz, nome);
            }
        }
        p += 7;
    }
    if (!out[0]) snprintf(out, outsz, "funções não extraídas do trecho lido");
}

static void md_extrair_paths(const char *txt, char *out, size_t outsz)
{
    if (!out || outsz == 0) return;
    out[0] = '\0';
    const char *p = txt ? txt : "";
    while ((p = strchr(p, '"')) != NULL) {
        p++;
        char s[256]; size_t j = 0; int esc = 0;
        for (; *p && j + 1 < sizeof(s); p++) {
            if (esc) { s[j++] = *p; esc = 0; continue; }
            if (*p == '\\') { esc = 1; continue; }
            if (*p == '"') break;
            s[j++] = *p;
        }
        s[j] = '\0';
        if ((strchr(s, '/') || strstr(s, ".json") || strstr(s, ".c") || strstr(s, ".php")) && strlen(s) > 2 && strlen(s) < 180) md_add_token(out, outsz, s);
        if (*p == '"') p++;
    }
    if (!out[0]) snprintf(out, outsz, "nenhum caminho literal relevante detectado");
}

static int md_json_get_string(const char *txt, const char *key, char *out, size_t outsz)
{
    if (!out || outsz == 0) return 0;
    out[0] = '\0';
    char pad[128]; snprintf(pad, sizeof(pad), "\"%s\"", key);
    const char *p = strstr(txt ? txt : "", pad);
    if (!p) return 0;
    p = strchr(p + strlen(pad), ':');
    if (!p) return 0;
    p++;
    while (*p && isspace((unsigned char)*p)) p++;
    if (*p != '"') return 0;
    p++;
    char tmp[1200]; size_t j = 0; int esc = 0;
    for (; *p && j + 1 < sizeof(tmp); p++) {
        if (esc) { tmp[j++] = *p; esc = 0; continue; }
        if (*p == '\\') { esc = 1; continue; }
        if (*p == '"') break;
        tmp[j++] = *p;
    }
    tmp[j] = '\0';
    md_compactar_texto(tmp, out, outsz);
    return out[0] != '\0';
}

static void md_resumir_json(const char *path, char *out, size_t outsz)
{
    char sig[160]; md_assinatura_path(path, sig, sizeof(sig));
    size_t n = 0; char *txt = md_ler_arquivo_limite(path, 65536, &n);
    if (!txt) { snprintf(out, outsz, "%s — ausente", path); return; }
    char nome[260] = "", titulo[420] = "", desc[900] = "", objetivo[900] = "";
    md_json_get_string(txt, "nome", nome, sizeof(nome));
    md_json_get_string(txt, "titulo", titulo, sizeof(titulo));
    md_json_get_string(txt, "descricao", desc, sizeof(desc));
    md_json_get_string(txt, "objetivo", objetivo, sizeof(objetivo));
    snprintf(out, outsz, "%s — %s; nome=%s; titulo=%s; descricao/objetivo=%s%s%s",
             path, sig,
             nome[0] ? nome : "não extraído",
             titulo[0] ? titulo : "não extraído",
             desc[0] ? desc : (objetivo[0] ? objetivo : "não extraído"),
             n >= 65536 ? "; trecho limitado a 64KiB" : "",
             "");
    free(txt);
}

static void md_resumir_comando(const char *raiz, const char *nome, char *out, size_t outsz)
{
    char src[PATH_MAX * 2], exe[PATH_MAX * 2], ajuda[PATH_MAX * 2], agente_json[PATH_MAX * 2];
    snprintf(src, sizeof(src), "%s/core/comandos/%s.c", raiz, nome);
    snprintf(exe, sizeof(exe), "%s/core/comandos/%s", raiz, nome);
    snprintf(ajuda, sizeof(ajuda), "%s/ajuda/%s.json", raiz, nome);
    snprintf(agente_json, sizeof(agente_json), "%s/core/biblioteca-agentes-fixos/%s.json", raiz, nome);
    char sig_src[160], sig_exe[160], sig_ajuda[160], sig_agente[160];
    md_assinatura_path(src, sig_src, sizeof(sig_src));
    md_assinatura_path(exe, sig_exe, sizeof(sig_exe));
    md_assinatura_path(ajuda, sig_ajuda, sizeof(sig_ajuda));
    md_assinatura_path(agente_json, sig_agente, sizeof(sig_agente));

    size_t nsrc = 0, naj = 0;
    char *txt_src = md_ler_arquivo_limite(src, 98304, &nsrc);
    if (!txt_src) {
        size_t nex = 0;
        char *txt_exe = md_ler_arquivo_limite(exe, 65536, &nex);
        if (txt_exe && nex >= 2 && txt_exe[0] == '#' && txt_exe[1] == '!') { txt_src = txt_exe; nsrc = nex; }
        else free(txt_exe);
    }
    char *txt_aj = md_ler_arquivo_limite(ajuda, 65536, &naj);
    char flags_src[900], flags_aj[700], funcs[700], paths[900], aj_nome[180] = "", aj_desc[700] = "", agente_resumo[1200] = "";
    md_extrair_flags(txt_src ? txt_src : "", flags_src, sizeof(flags_src));
    md_extrair_flags(txt_aj ? txt_aj : "", flags_aj, sizeof(flags_aj));
    md_extrair_funcoes_c(txt_src ? txt_src : "", funcs, sizeof(funcs));
    md_extrair_paths(txt_src ? txt_src : "", paths, sizeof(paths));
    if (txt_aj) {
        md_json_get_string(txt_aj, "nome", aj_nome, sizeof(aj_nome));
        md_json_get_string(txt_aj, "descricao", aj_desc, sizeof(aj_desc));
    }
    if (strcmp(sig_agente, "ausente") != 0) md_resumir_json(agente_json, agente_resumo, sizeof(agente_resumo));

    char alerta[260] = "";
    struct stat st_src, st_exe, st_ajuda;
    int tem_src = stat(src, &st_src) == 0 && S_ISREG(st_src.st_mode);
    int tem_exe = stat(exe, &st_exe) == 0 && S_ISREG(st_exe.st_mode);
    int tem_ajuda = stat(ajuda, &st_ajuda) == 0 && S_ISREG(st_ajuda.st_mode);
    if (tem_src && (!tem_exe || st_src.st_mtime > st_exe.st_mtime)) snprintf(alerta, sizeof(alerta), "; ALERTA fonte mais nova que executável");
    else if ((tem_src || tem_exe) && tem_ajuda && ((tem_src ? st_src.st_mtime : st_exe.st_mtime) > st_ajuda.st_mtime)) snprintf(alerta, sizeof(alerta), "; alerta ajuda possivelmente desatualizada");

    snprintf(out, outsz,
             "Código lido: %s — fonte/script lido: %s; executável/script: %s; ajuda: %s; manifesto agente: %s%s; flags no código/script: %s; flags na ajuda: %s; funções detectadas: %s; caminhos literais: %s; ajuda.nome=%s; ajuda.descricao=%s%s%s%s%s",
             nome, sig_src, sig_exe, sig_ajuda, sig_agente, alerta, flags_src, flags_aj, funcs, paths,
             aj_nome[0] ? aj_nome : "não extraído", aj_desc[0] ? aj_desc : "não extraída",
             agente_resumo[0] ? "; " : "", agente_resumo,
             nsrc >= 98304 ? "; fonte lida parcialmente 96KiB" : "", naj >= 65536 ? "; ajuda lida parcialmente 64KiB" : "");
    free(txt_src); free(txt_aj);
}

static void md_resumir_arquivo_rel(const char *raiz, const char *rel, char *out, size_t outsz)
{
    if (!md_rel_eh_fonte_codigo_sisc(rel)) {
        snprintf(out, outsz, "LEI FONTE-CÓDIGO: %s — não usado como fonte de pesquisa; classificado como contexto de entendimento/uso, runtime, credencial ou artefato gerado, não como código integrante do funcionamento do SISC", rel ? rel : "(nulo)");
        return;
    }
    char path[PATH_MAX * 2], sig[160];
    snprintf(path, sizeof(path), "%s/%s", raiz, rel);
    md_assinatura_path(path, sig, sizeof(sig));
    char resumo[1400] = "";
    if (strstr(rel, ".json")) md_resumir_json(path, resumo, sizeof(resumo));
    else {
        size_t n = 0; char *txt = md_ler_arquivo_limite(path, 49152, &n);
        if (txt) {
            char flags[500], funcs[500], paths[500];
            md_extrair_flags(txt, flags, sizeof(flags));
            md_extrair_funcoes_c(txt, funcs, sizeof(funcs));
            md_extrair_paths(txt, paths, sizeof(paths));
            snprintf(resumo, sizeof(resumo), "%s — %s; flags=%s; funções=%s; caminhos=%s%s", rel, sig, flags, funcs, paths, n >= 49152 ? "; trecho lido 48KiB" : "");
            free(txt);
        } else snprintf(resumo, sizeof(resumo), "%s — %s", rel, sig);
    }
    snprintf(out, outsz, "%s", resumo);
}

#endif
