/*
 * pp - Roteador de comandos do sistema
 * Uso: pp [--]<comando> [argumentos...]
 *
 * Encaminha a execução para o programa correspondente em core/comandos/.
 * Exemplo: pp --criar-conta-llm arg1 arg2
 *          -> executa core/comandos/criar-conta-llm arg1 arg2
 */

#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>
#include <limits.h>
#include <libgen.h>
#include <ctype.h>
#include <stddef.h>
#include <sys/types.h>
#include <sys/wait.h>

static int ajuda_arg_exato(const char *arg)
{
    return arg && (strcmp(arg, "--ajuda") == 0 || strcmp(arg, "--help") == 0 || strcmp(arg, "-h") == 0);
}

static const char *ajuda_arg_filtro(const char *arg)
{
    if (!arg) return NULL;
    if (strncmp(arg, "--ajuda=", 8) == 0) return arg + 8;
    if (strncmp(arg, "--ajuda:", 8) == 0) return arg + 8;
    if (strncmp(arg, "--help=", 7) == 0) return arg + 7;
    if (strncmp(arg, "--help:", 7) == 0) return arg + 7;
    return NULL;
}

static int ajuda_arg_qualquer(const char *arg)
{
    return ajuda_arg_exato(arg) || ajuda_arg_filtro(arg) != NULL;
}

static const char *proc_arg_filtro(const char *arg)
{
    if (!arg) return NULL;
    if (strncmp(arg, "--proc=", 7) == 0) return arg + 7;
    return NULL;
}

static int sa_ajuda_arg_permitido(const char *arg)
{
    return ajuda_arg_qualquer(arg) || proc_arg_filtro(arg) != NULL;
}

static int flag_delim(int c)
{
    return c == '\0' || isspace((unsigned char)c) || c == '=' || c == ',' ||
           c == '<' || c == '[' || c == ']' || c == ')' || c == ':' || c == ';';
}

static int flag_inicio_delim(int c)
{
    return c == '\0' || isspace((unsigned char)c) || c == ',' || c == '(' || c == '[';
}

static void normalizar_filtro_flag(const char *filtro, char *longo, size_t longo_sz,
                                   char *curto, size_t curto_sz)
{
    char nome[128];
    size_t n = 0;
    const char *p = filtro ? filtro : "";
    while (*p == '-') p++;
    while (*p && *p != '=' && !isspace((unsigned char)*p) && n + 1 < sizeof(nome)) {
        nome[n++] = *p++;
    }
    nome[n] = '\0';
    if (nome[0]) snprintf(longo, longo_sz, "--%s", nome);
    else snprintf(longo, longo_sz, "--");
    if (n == 1 && curto_sz >= 3) {
        curto[0] = '-';
        curto[1] = nome[0];
        curto[2] = '\0';
    } else if (curto_sz) curto[0] = '\0';
}

static int texto_contem_flag(const char *ini, const char *fim, const char *flag, int curto)
{
    size_t flen = strlen(flag);
    if (!flag[0]) return 0;
    for (const char *p = ini; p && p < fim; p++) {
        const char *m = strstr(p, flag);
        if (!m || m >= fim) return 0;
        if (m + flen <= fim && flag_delim((unsigned char)m[flen]) &&
            (!curto || m == ini || (flag_inicio_delim((unsigned char)m[-1]) && m[-1] != '-'))) {
            return 1;
        }
        p = m;
    }
    return 0;
}

static char ascii_lower_char(unsigned char c)
{
    if (c >= 'A' && c <= 'Z') return (char)(c - 'A' + 'a');
    return (char)c;
}

static void normalizar_filtro_grupo(const char *filtro, char *out, size_t out_sz)
{
    if (!out || out_sz == 0) return;
    const char *p = filtro ? filtro : "";
    while (*p == '-') p++;
    size_t n = 0;
    while (*p && *p != '=' && !isspace((unsigned char)*p) && n + 1 < out_sz) {
        out[n++] = ascii_lower_char((unsigned char)*p++);
    }
    out[n] = '\0';
}

static int texto_contem_ci(const char *ini, const char *fim, const char *agulha)
{
    size_t n = strlen(agulha);
    if (!n) return 0;
    for (const char *p = ini; p + (ptrdiff_t)n <= fim; p++) {
        size_t i = 0;
        while (i < n && p + (ptrdiff_t)i < fim &&
               ascii_lower_char((unsigned char)p[i]) == ascii_lower_char((unsigned char)agulha[i])) i++;
        if (i == n) return 1;
    }
    return 0;
}

static int bloco_titulo_contem_grupo(const char *ini, const char *fim, const char *grupo)
{
    if (!grupo || !*grupo) return 0;
    const char *p = ini;
    while (p < fim && (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r')) p++;
    const char *linha_fim = memchr(p, '\n', (size_t)(fim - p));
    if (!linha_fim) linha_fim = fim;
    if (*p == '#') return 0;
    if ((size_t)(linha_fim - p) >= 3 && ascii_lower_char((unsigned char)p[0]) == 'p' &&
        ascii_lower_char((unsigned char)p[1]) == 'p' && p[2] == ' ') return 0;
    if (texto_contem_ci(p, linha_fim, "grupos de ajuda:")) return 0;
    return texto_contem_ci(p, linha_fim, grupo);
}

static int bloco_contem_flag(const char *ini, const char *fim, const char *longo, const char *curto)
{
    return texto_contem_flag(ini, fim, longo, 0) ||
           (curto && curto[0] && texto_contem_flag(ini, fim, curto, 1));
}

static int filtrar_ajuda_por_flag(const char *saida, const char *filtro)
{
    char longo[160], curto[8], grupo[128];
    int encontrou_flag = 0, encontrou_grupo = 0;
    normalizar_filtro_flag(filtro, longo, sizeof(longo), curto, sizeof(curto));
    normalizar_filtro_grupo(filtro, grupo, sizeof(grupo));

    /* Prioridade 1: filtro por flag real (--ag, --dry-run etc.).
     * Isso evita que --ajuda:ag bata acidentalmente no titulo "ajuda". */
    for (const char *ini = saida; *ini;) {
        const char *sep = strstr(ini, "\n\n");
        const char *fim = sep ? sep : ini + strlen(ini);
        if (bloco_contem_flag(ini, fim, longo, curto)) {
            encontrou_flag = 1;
        }
        if (!sep) break;
        ini = sep + 2;
    }

    /* Prioridade 2: filtro por grupo/titulo, quando nao existe flag com esse nome. */
    if (!encontrou_flag) {
        for (const char *ini = saida; *ini;) {
            const char *sep = strstr(ini, "\n\n");
            const char *fim = sep ? sep : ini + strlen(ini);
            if (bloco_titulo_contem_grupo(ini, fim, grupo)) {
                encontrou_grupo = 1;
            }
            if (!sep) break;
            ini = sep + 2;
        }
    }

    if (!encontrou_flag && !encontrou_grupo) {
        fprintf(stderr, "pp: nenhum grupo de ajuda contem '%s'.\n", filtro ? filtro : "");
        fputs(saida, stdout);
        return 1;
    }

    int impresso = 0;
    for (const char *ini = saida; *ini;) {
        const char *sep = strstr(ini, "\n\n");
        const char *fim = sep ? sep : ini + strlen(ini);
        int ok = 0;
        if (encontrou_grupo) ok = bloco_titulo_contem_grupo(ini, fim, grupo);
        else ok = bloco_contem_flag(ini, fim, longo, curto);
        if (ok) {
            if (impresso) putchar('\n');
            fwrite(ini, 1, (size_t)(fim - ini), stdout);
            putchar('\n');
            impresso = 1;
        }
        if (!sep) break;
        ini = sep + 2;
    }
    return 0;
}

static int executar_com_ajuda_filtrada(const char *cmd_path, char **novo_argv,
                                       const char *nome_comando, const char *dir,
                                       const char *filtro)
{
    int fd[2];
    if (pipe(fd) != 0) {
        perror("pp: pipe");
        return EXIT_FAILURE;
    }

    pid_t pid = fork();
    if (pid < 0) {
        perror("pp: fork");
        close(fd[0]); close(fd[1]);
        return EXIT_FAILURE;
    }
    if (pid == 0) {
        close(fd[0]);
        if (dup2(fd[1], STDOUT_FILENO) < 0) _exit(126);
        close(fd[1]);
        execv(cmd_path, novo_argv);
        fprintf(stderr, "pp: comando '%s' não encontrado em '%s/core/comandos/'\n", nome_comando, dir);
        _exit(127);
    }

    close(fd[1]);
    char *buf = NULL;
    size_t len = 0, cap = 0;
    char tmp[4096];
    ssize_t r;
    while ((r = read(fd[0], tmp, sizeof(tmp))) > 0) {
        if (len + (size_t)r + 1 > cap) {
            size_t novo_cap = cap ? cap * 2 : 8192;
            while (novo_cap < len + (size_t)r + 1) novo_cap *= 2;
            char *nb = realloc(buf, novo_cap);
            if (!nb) {
                free(buf);
                close(fd[0]);
                waitpid(pid, NULL, 0);
                fprintf(stderr, "pp: erro de alocação de memória\n");
                return EXIT_FAILURE;
            }
            buf = nb;
            cap = novo_cap;
        }
        memcpy(buf + len, tmp, (size_t)r);
        len += (size_t)r;
    }
    close(fd[0]);
    if (!buf) {
        buf = malloc(1);
        if (!buf) {
            waitpid(pid, NULL, 0);
            fprintf(stderr, "pp: erro de alocação de memória\n");
            return EXIT_FAILURE;
        }
    }
    buf[len] = '\0';

    int status = 0;
    waitpid(pid, &status, 0);
    int filtro_status = filtrar_ajuda_por_flag(buf, filtro);
    free(buf);

    if (filtro_status == 0) return 0;
    if (WIFEXITED(status) && WEXITSTATUS(status) != 0) return WEXITSTATUS(status);
    if (WIFSIGNALED(status)) return 128 + WTERMSIG(status);
    return filtro_status;
}

static int comando_somente_dados_cwd(const char *comando)
{
    return comando && strcmp(comando, "sa") == 0;
}

static int validar_diretorio_sistema(const char *raiz_sisc, const char *comando)
{
    /* Restrição de diretório desativada para todos os comandos. */
    (void)raiz_sisc;
    (void)comando;
    return 1;
}

static char *ler_arquivo_limitado(const char *path, size_t max_bytes)
{
    FILE *f = fopen(path, "rb");
    if (!f) return NULL;
    if (fseek(f, 0, SEEK_END) != 0) { fclose(f); return NULL; }
    long tam = ftell(f);
    if (tam < 0 || (size_t)tam > max_bytes) { fclose(f); return NULL; }
    rewind(f);
    char *buf = malloc((size_t)tam + 1);
    if (!buf) { fclose(f); return NULL; }
    size_t n = fread(buf, 1, (size_t)tam, f);
    int erro = ferror(f);
    fclose(f);
    if (erro) { free(buf); return NULL; }
    buf[n] = '\0';
    return buf;
}

static char *json_extrair_string_simples(const char *json, const char *chave)
{
    if (!json || !chave || !*chave) return NULL;
    char padrao[256];
    snprintf(padrao, sizeof(padrao), "\"%s\"", chave);
    const char *p = strstr(json, padrao);
    if (!p) return NULL;
    p = strchr(p + strlen(padrao), ':');
    if (!p) return NULL;
    p++;
    while (*p && isspace((unsigned char)*p)) p++;
    if (*p != '"') return NULL;
    p++;
    size_t cap = 128, len = 0;
    char *out = malloc(cap);
    if (!out) return NULL;
    while (*p && *p != '"') {
        char c = *p++;
        if (c == '\\' && *p) {
            c = *p++;
            if (c == 'n') c = '\n';
            else if (c == 't') c = '\t';
            else if (c == 'r') c = '\r';
        }
        if (len + 1 >= cap) {
            cap *= 2;
            char *nb = realloc(out, cap);
            if (!nb) { free(out); return NULL; }
            out = nb;
        }
        out[len++] = c;
    }
    out[len] = '\0';
    return out;
}

static char *json_extrair_string_ate(const char *json, const char *chave, const char *limite)
{
    if (!json || !chave || !*chave) return NULL;
    char padrao[256];
    snprintf(padrao, sizeof(padrao), "\"%s\"", chave);
    const char *p = strstr(json, padrao);
    if (!p || (limite && p >= limite)) return NULL;
    p = strchr(p + strlen(padrao), ':');
    if (!p || (limite && p >= limite)) return NULL;
    p++;
    while (*p && isspace((unsigned char)*p)) p++;
    if ((limite && p >= limite) || *p != '"') return NULL;
    p++;
    size_t cap = 128, len = 0;
    char *out = malloc(cap);
    if (!out) return NULL;
    while (*p && *p != '"' && (!limite || p < limite)) {
        char c = *p++;
        if (c == '\\' && *p && (!limite || p < limite)) {
            c = *p++;
            if (c == 'n') c = '\n';
            else if (c == 't') c = '\t';
            else if (c == 'r') c = '\r';
        }
        if (len + 1 >= cap) {
            cap *= 2;
            char *nb = realloc(out, cap);
            if (!nb) { free(out); return NULL; }
            out = nb;
        }
        out[len++] = c;
    }
    out[len] = '\0';
    return out;
}

static char *mapa_comandos_primeiro_filho_nome(const char *obj)
{
    const char *filhos = strstr(obj, "\"filhos\"");
    if (!filhos) return NULL;
    const char *abre = strchr(filhos, '[');
    if (!abre) return NULL;
    const char *fecha = strchr(abre, ']');
    const char *nome = strstr(abre, "\"nome\"");
    if (!nome || !fecha || nome > fecha) return NULL;
    return json_extrair_string_ate(nome, "nome", fecha);
}

static char *mapa_comandos_sa_conta(const char *json, const char *comando)
{
    char *tipo = json_extrair_string_simples(json, "tipo");
    int eh_sa = tipo && strcmp(tipo, "arvore-sa") == 0;
    free(tipo);
    if (!eh_sa || !comando || !*comando) return NULL;

    char chave_alt[PATH_MAX];
    snprintf(chave_alt, sizeof(chave_alt), "%s%s", strncmp(comando, "--", 2) == 0 ? "" : "--", comando);

    const char *p = json;
    while ((p = strstr(p, "\"nome\"")) != NULL) {
        const char *prox = strstr(p + 6, "\"nome\"");
        char *nome = json_extrair_string_ate(p, "nome", prox);
        int achou = nome && (strcmp(nome, comando) == 0 || strcmp(nome, chave_alt) == 0);
        free(nome);
        if (achou) {
            char *conta = json_extrair_string_ate(p, "mm", prox);
            if (!conta) conta = json_extrair_string_ate(p, "valor", prox);
            if (!conta) conta = mapa_comandos_primeiro_filho_nome(p);
            return conta;
        }
        p += 6;
    }
    return NULL;
}

static void normalizar_conta_llm(const char *valor, char *out, size_t out_sz)
{
    if (!out || out_sz == 0) return;
    out[0] = '\0';
    if (!valor) return;
    while (*valor && isspace((unsigned char)*valor)) valor++;
    size_t len = strlen(valor);
    while (len > 0 && isspace((unsigned char)valor[len - 1])) len--;
    if (len == 0 || len >= out_sz) return;
    char tmp[PATH_MAX];
    if (len >= sizeof(tmp)) return;
    memcpy(tmp, valor, len);
    tmp[len] = '\0';
    for (size_t i = 0; tmp[i]; i++) {
        unsigned char c = (unsigned char)tmp[i];
        if (!(isalnum(c) || c == '.' || c == '_' || c == '-')) return;
    }
    snprintf(out, out_sz, "%s", tmp);
    size_t n = strlen(out);
    if (n < 5 || strcmp(out + n - 5, ".json") != 0) {
        if (n + 5 >= out_sz) { out[0] = '\0'; return; }
        strcat(out, ".json");
    }
}

static int resolver_conta_llm_mapeada(const char *raiz_sisc, const char *comando,
                                      int somente_cwd, char *out, size_t out_sz)
{
    if (!comando || !*comando || !out || out_sz == 0) return 0;
    out[0] = '\0';

    char mapas[2][PATH_MAX * 2];
    char cwd[PATH_MAX];
    if (getcwd(cwd, sizeof(cwd))) snprintf(mapas[0], sizeof(mapas[0]), "%s/config/mapa-comandos.json", cwd);
    else mapas[0][0] = '\0';
    if (somente_cwd) mapas[1][0] = '\0';
    else snprintf(mapas[1], sizeof(mapas[1]), "%s/core/config/mapa-comandos.json", raiz_sisc ? raiz_sisc : "");

    for (int i = 0; i < 2; i++) {
        if (!mapas[i][0]) continue;
        char *json = ler_arquivo_limitado(mapas[i], 1024 * 1024);
        if (!json) continue;
        char *valor = mapa_comandos_sa_conta(json, comando);
        if (!valor) valor = json_extrair_string_simples(json, comando);
        if (!valor && strncmp(comando, "--", 2) != 0) {
            char chave[PATH_MAX];
            snprintf(chave, sizeof(chave), "--%s", comando);
            valor = json_extrair_string_simples(json, chave);
        }
        if (valor) normalizar_conta_llm(valor, out, out_sz);
        free(valor);
        free(json);
        if (out[0]) return 1;
    }
    return 0;
}

static int nome_comando_seguro(const char *s)
{
    if (!s || !*s) return 0;
    for (const char *p = s; *p; p++) {
        unsigned char c = (unsigned char)*p;
        if (!(isalnum(c) || c == '.' || c == '_' || c == '-')) return 0;
    }
    return 1;
}

static int ajuda_json_existe(const char *dir, const char *comando)
{
    if (!dir || !comando || !nome_comando_seguro(comando)) return 0;
    char path[PATH_MAX * 2];
    snprintf(path, sizeof(path), "%s/ajuda/%s.json", dir, comando);
    return access(path, R_OK) == 0;
}

static int executar_ajuda_via_sa(const char *dir, const char *comando, const char *filtro)
{
    char parent[PATH_MAX];
    snprintf(parent, sizeof(parent), "%s", dir ? dir : "");
    char *base = strrchr(parent, '/');
    if (!base || !base[1]) {
        fprintf(stderr, "pp: nao foi possivel resolver sisc/ajuda para '%s'\n", comando ? comando : "");
        return EXIT_FAILURE;
    }
    *base++ = '\0';

    char pp_path[PATH_MAX * 2];
    snprintf(pp_path, sizeof(pp_path), "%s/pp", dir);

    char sa_arg[PATH_MAX * 2];
    snprintf(sa_arg, sizeof(sa_arg), "--sa=%s/ajuda/%s.json", base, comando);

    char proc_arg[PATH_MAX * 2];
    char *args[4];
    args[0] = pp_path;
    args[1] = sa_arg;
    if (filtro && *filtro) {
        snprintf(proc_arg, sizeof(proc_arg), "--proc=%s", filtro);
        args[2] = proc_arg;
        args[3] = NULL;
    } else {
        args[2] = NULL;
    }

    if (chdir(parent) != 0) {
        perror("pp: chdir ajuda");
        return EXIT_FAILURE;
    }
    execv(pp_path, args);
    perror("pp: exec ajuda via --sa");
    return EXIT_FAILURE;
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        fprintf(stderr, "Uso: pp [--]<comando> [argumentos...]\n");
        fprintf(stderr, "Exemplo: pp criar-conta-llm\n");
        return EXIT_FAILURE;
    }

    const char *flag = argv[1];

    /* Valida formato [--]<comando> */
    if (strncmp(flag, "--", 2) == 0) {
        if (strlen(flag) <= 2) {
            fprintf(stderr, "pp: esperado um comando no formato [--]<comando>\n");
            fprintf(stderr, "Recebido: '%s'\n", flag);
            return EXIT_FAILURE;
        }
    } else if (flag[0] == '-') {
        fprintf(stderr, "pp: esperado um comando no formato [--]<comando>\n");
        fprintf(stderr, "Recebido: '%s'\n", flag);
        return EXIT_FAILURE;
    }

    /* Verifica sintaxe comando=valor ou comando:valor */
    const char *nome_comando = (strncmp(flag, "--", 2) == 0) ? flag + 2 : flag;
    char *valor_embutido = NULL;
    char *comando_dup = NULL;

    const char *separador = strchr(nome_comando, '=');
    const char *dois_pontos = strchr(nome_comando, ':');
    if (!separador || (dois_pontos && dois_pontos < separador)) separador = dois_pontos;
    if (separador) {
        /* Separa: atualizar-heb=siscore -> nome=atualizar-heb, valor=siscore
         * Separa também: infoarq:/caminho/arquivo -> nome=infoarq, valor=/caminho/arquivo */
        size_t tam_nome = (size_t)(separador - nome_comando);
        comando_dup = malloc(tam_nome + 1);
        if (!comando_dup) {
            fprintf(stderr, "pp: erro de alocação de memória\n");
            return EXIT_FAILURE;
        }
        memcpy(comando_dup, nome_comando, tam_nome);
        comando_dup[tam_nome] = '\0';
        nome_comando = comando_dup;
        valor_embutido = (char *)(separador + 1);
    }

    /* Valida que todas as flags usam prefixo -- (dois hifens) */
    for (int i = 2; i < argc; i++) {
        const char *a = argv[i];
        if (a[0] == '-' && strncmp(a, "--", 2) != 0) {
            /* permite -h sozinho como atalho para ajuda */
            if (strcmp(a, "-h") == 0) continue;
            /* permite numero negativo (ex: -1.655.00) */
            if (a[1] >= '0' && a[1] <= '9') continue;
            fprintf(stderr, "pp: flag '%s' inválida. Todas as flags devem usar '--' (ex: --%s).\n", a, a + 1);
            free(comando_dup);
            return EXIT_FAILURE;
        }
    }

    /* Descobre o diretório onde o pp está instalado (raiz do sisc) */
    char meu_path[PATH_MAX];
    ssize_t len = readlink("/proc/self/exe", meu_path, sizeof(meu_path) - 1);
    if (len == -1) {
        perror("pp: readlink /proc/self/exe");
        free(comando_dup);
        return EXIT_FAILURE;
    }
    meu_path[len] = '\0';

    char *dir = dirname(meu_path);

    if (!validar_diretorio_sistema(dir, nome_comando)) {
        free(comando_dup);
        return EXIT_FAILURE;
    }

    /* Monta o caminho: <dir>/core/comandos/<nome_comando> */
    char cmd_path[PATH_MAX];
    snprintf(cmd_path, sizeof(cmd_path), "%s/core/comandos/%s", dir, nome_comando);

    const char *filtro_ajuda = NULL;
    int pedido_ajuda = 0;
    int conta_llm_explicit = 0;
    for (int i = 2; i < argc; i++) {
        const char *fa = ajuda_arg_filtro(argv[i]);
        if (fa && !filtro_ajuda) filtro_ajuda = fa;
        if (ajuda_arg_qualquer(argv[i])) pedido_ajuda = 1;
        if (strncmp(argv[i], "--conta-llm=", 12) == 0) conta_llm_explicit = 1;
    }

    if (pedido_ajuda && strcmp(nome_comando, "sa") == 0) {
        for (int i = 2; i < argc; i++) {
            if (!sa_ajuda_arg_permitido(argv[i])) {
                fprintf(stderr, "pp: quando pp --sa é usado com --ajuda, somente --proc=<termo> pode ser combinado. Argumento recusado: %s\n", argv[i]);
                free(comando_dup);
                return EXIT_FAILURE;
            }
            const char *fp = proc_arg_filtro(argv[i]);
            if (fp && *fp) filtro_ajuda = fp;
        }
    }

    const char *nome_ajuda = nome_comando;
    if (pedido_ajuda && strcmp(nome_comando, "agente") == 0 && valor_embutido && ajuda_json_existe(dir, valor_embutido)) {
        nome_ajuda = valor_embutido;
    }
    if (pedido_ajuda && ajuda_json_existe(dir, nome_ajuda)) {
        int rc = executar_ajuda_via_sa(dir, nome_ajuda, filtro_ajuda);
        free(comando_dup);
        return rc;
    }

    if (!conta_llm_explicit && strcmp(nome_comando, "testar-contas-llm") != 0) {
        char conta_mapeada[PATH_MAX];
        if (resolver_conta_llm_mapeada(dir, nome_comando, comando_somente_dados_cwd(nome_comando), conta_mapeada, sizeof(conta_mapeada))) {
            setenv("SISC_CONTA_LLM", conta_mapeada, 1);
        }
    }

    /* Constrói o vetor de argumentos para o comando filho.
     * --conta-llm=... é aceito globalmente por qualquer comando via pp:
     * o roteador remove esse argumento da lista do filho e expõe em SISC_CONTA_LLM.
     * Quando a flag não é informada, pp procura config/mapa-comandos.json
     * no sistema atual e depois core/config/mapa-comandos.json, expondo a
     * conta mapeada também via SISC_CONTA_LLM.
     * Comandos que usam LLM podem consumir a variável; comandos sem LLM simplesmente ignoram.
     * O valor embutido pode vir por --comando=valor ou --comando:valor.
     * --ajuda=<flag> / --ajuda:<flag> usa ajuda/<comando>.json via pp --sa quando
     * existir; sem JSON dedicado, mantém o filtro textual legado do pp. */
    char **novo_argv = malloc(((size_t)argc + 2) * sizeof(char *));
    if (!novo_argv) {
        fprintf(stderr, "pp: erro de alocação de memória\n");
        free(comando_dup);
        return EXIT_FAILURE;
    }

    int pos = 0;
    /* Use o caminho real como argv[0]; scripts com shebang podem travar quando argv[0]
     * não aponta para o arquivo executado. O comando ainda recupera o nome via basename. */
    novo_argv[pos++] = cmd_path;
    if (valor_embutido && (!pedido_ajuda || strcmp(nome_comando, "agente") == 0)) {
        /* --agente=<nome> --ajuda precisa preservar <nome> para exibir a ajuda
         * especifica do agente. Nos demais comandos, mantem o comportamento
         * historico: ajuda com valor embutido mostra a ajuda geral do comando. */
        novo_argv[pos++] = valor_embutido;
    }
    for (int i = 2; i < argc; i++) {
        if (strncmp(argv[i], "--conta-llm=", 12) == 0) {
            setenv("SISC_CONTA_LLM", argv[i] + 12, 1);
            setenv("SISC_CONTA_LLM_EXPLICITA", "1", 1);
            continue;
        }
        if (ajuda_arg_filtro(argv[i])) {
            novo_argv[pos++] = "--ajuda";
            continue;
        }
        if (strcmp(argv[i], "--help") == 0) {
            novo_argv[pos++] = "--ajuda";
            continue;
        }
        novo_argv[pos++] = argv[i];
    }
    novo_argv[pos] = NULL;

    if (filtro_ajuda) {
        int rc = executar_com_ajuda_filtrada(cmd_path, novo_argv, nome_comando, dir, filtro_ajuda);
        free(novo_argv);
        free(comando_dup);
        return rc;
    }

    execv(cmd_path, novo_argv);

    /* Se chegou aqui, execv falhou */
    fprintf(stderr, "pp: comando '%s' não encontrado em '%s/core/comandos/'\n",
            nome_comando, dir);
    free(novo_argv);
    free(comando_dup);
    return EXIT_FAILURE;
}
