/*
 * atualizar-manual-funcional - atualiza a árvore viva operador-manual-funcional do SISC
 *
 * Uso:
 *   pp --atualizar-manual-funcional [opções do mapa] [flags do --sa]
 *
 * Compatibilidade:
 *   pp --sa --mapa encaminha para este comando.
 *
 * Este comando cria exclusivamente a árvore canônica:
 *   sisc/arvores/operador-manual-funcional.json
 *
 * Não cria mapas legados e não salva mapas em sisc/<sistema>/arvores.
 */

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

#ifndef PATH_MAX
#define PATH_MAX 4096
#endif

static int caminho_comando_irmao(const char *nome, char *out, size_t tam)
{
    char exe[PATH_MAX];
    ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
    if (n <= 0) return -1;
    exe[n] = '\0';
    char *slash = strrchr(exe, '/');
    if (!slash) return -1;
    *slash = '\0';
    size_t a = strlen(exe), b = strlen(nome);
    if (a + 1 + b + 1 > tam) return -1;
    memcpy(out, exe, a);
    out[a] = '/';
    memcpy(out + a + 1, nome, b + 1);
    return 0;
}

static int localizar_raiz_sisc(char *out, size_t tam)
{
    char exe[PATH_MAX];
    ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
    if (n <= 0) return -1;
    exe[n] = '\0';
    /* /.../sisc/core/comandos/atualizar-manual-funcional -> /.../sisc */
    char *slash = strrchr(exe, '/'); if (!slash) return -1; *slash = '\0';
    slash = strrchr(exe, '/'); if (!slash) return -1; *slash = '\0';
    slash = strrchr(exe, '/'); if (!slash) return -1; *slash = '\0';
    return snprintf(out, tam, "%s", exe) < (int)tam ? 0 : -1;
}

static const char *base_name_local(const char *path)
{
    const char *p = strrchr(path ? path : "", '/');
    return p ? p + 1 : (path ? path : "");
}

static int eh_dir(const char *path)
{
    struct stat st;
    return path && stat(path, &st) == 0 && S_ISDIR(st.st_mode);
}

static void detectar_sistema_alvo(const char *raiz_sisc, int argc, char **argv, char *out, size_t outsz)
{
    if (!out || outsz == 0) return;
    out[0] = '\0';

    for (int i = 1; i < argc; i++) {
        if (strncmp(argv[i], "--sistema=", 10) == 0 && argv[i][10]) {
            snprintf(out, outsz, "%s", argv[i] + 10);
            return;
        }
    }

    char cwd[PATH_MAX];
    if (getcwd(cwd, sizeof(cwd)) && raiz_sisc && *raiz_sisc) {
        size_t rl = strlen(raiz_sisc);
        if (strcmp(cwd, raiz_sisc) == 0) {
            char siscore[PATH_MAX * 2];
            snprintf(siscore, sizeof(siscore), "%s/siscore", raiz_sisc);
            snprintf(out, outsz, "%s", eh_dir(siscore) ? "siscore" : base_name_local(raiz_sisc));
            return;
        }
        if (strncmp(cwd, raiz_sisc, rl) == 0 && cwd[rl] == '/') {
            const char *p = cwd + rl + 1;
            size_t n = strcspn(p, "/");
            if (n > 0 && n + 1 < outsz) {
                memcpy(out, p, n);
                out[n] = '\0';
                return;
            }
        }
    }
    snprintf(out, outsz, "siscore");
}

static int eh_ajuda(const char *a)
{
    return a && (!strcmp(a, "--ajuda") || !strcmp(a, "--help") || !strcmp(a, "-h"));
}

static int arg_de_nome_legado(const char *a)
{
    return a && a[0] && a[0] != '-';
}

static int arg_ignorado_no_repasse(const char *a)
{
    if (!a) return 1;
    if (!strcmp(a, "--mapa") || !strncmp(a, "--mapa=", 7)) return 1;
    if (!strncmp(a, "--sa=", 5)) return 1; /* alias legado pp --sa=<x> --mapa: saída agora é fixa */
    if (arg_de_nome_legado(a)) return 1; /* nome legado ignorado: sempre operador-manual-funcional */
    return 0;
}

static void ajuda(void)
{
    fputs(
        "Uso:\n"
        "  pp --atualizar-manual-funcional [opções do mapa] [flags do --sa]\n"
        "  pp --sa --mapa [opções]              Alias legado para este comando\n"
        "\n"
        "Descrição:\n"
        "  Revarre o SISC e atualiza somente a árvore viva de contexto funcional:\n"
        "    sisc/arvores/operador-manual-funcional.json\n"
        "  Não cria mapas legados e não grava em sisc/<sistema>/arvores.\n"
        "  Depois exibe/manipula a árvore gerada via --sa.\n"
        "\n"
        "Opções do mapa:\n"
        "  --atualizar, --recriar          Recria o mapa; a regeneração já é padrão\n"
        "  --incluir-ocultos              Inclui nomes iniciados por ponto\n"
        "  --incluir-ignorados            Inclui diretórios normalmente ignorados\n"
        "  --incluir-secretos             Inclui secretos; use com cuidado\n"
        "  --incluir-codigo               Inclui amostras/símbolos dos atores não-comando\n"
        "  --max-prof=N                   Limita profundidade\n"
        "  --exceto=.ext1,.ext2,...        Exclui arquivos pela extensão\n"
        "  --sistema=<nome>               Filtra core/ + sistema informado; padrão: sistema atual ou siscore\n"
        "\n"
        "Flags repassadas ao --sa:\n"
        "  --json, --gc=, --mm=, --prompt=, --rel, --ra=, --dra, --recolher=,\n"
        "  --expandir=, --replace= e demais flags aceitas por pp --sa.\n"
        "\n"
        "Exemplos:\n"
        "  pp --atualizar-manual-funcional\n"
        "  pp --atualizar-manual-funcional --json\n"
        "  pp --atualizar-manual-funcional --sistema=siscore --exceto=.,.json --max-prof=3\n"
        "  pp --sa --mapa                  # compatibilidade\n",
        stdout);
}

static int gerar_mapa_funcional(int argc, char **argv, const char *json_path, const char *sistema_alvo)
{
    char cmd[PATH_MAX];
    if (caminho_comando_irmao("sa-mapa", cmd, sizeof(cmd)) != 0) {
        fprintf(stderr, "atualizar-manual-funcional: não foi possível localizar o comando sa-mapa.\n");
        return 1;
    }

    char sist_arg[PATH_MAX + 16];
    snprintf(sist_arg, sizeof(sist_arg), "--sistema=%s", sistema_alvo && *sistema_alvo ? sistema_alvo : "siscore");

    char **margs = calloc((size_t)argc + 8, sizeof(char *));
    if (!margs) return 1;

    int pos = 0;
    margs[pos++] = cmd;
    margs[pos++] = (char *)json_path;
    margs[pos++] = sist_arg;
    for (int i = 1; i < argc; i++) {
        if (arg_ignorado_no_repasse(argv[i])) continue;
        margs[pos++] = argv[i];
    }
    margs[pos] = NULL;

    pid_t pid = fork();
    if (pid < 0) { perror("atualizar-manual-funcional: fork"); free(margs); return 1; }
    if (pid == 0) {
        setenv("SISC_SA_MAPA_SOMENTE_GERAR", "1", 1);
        execv(cmd, margs);
        perror("atualizar-manual-funcional: execv sa-mapa");
        _exit(127);
    }

    int st = 0;
    if (waitpid(pid, &st, 0) < 0) { perror("atualizar-manual-funcional: waitpid"); free(margs); return 1; }
    free(margs);
    if (WIFEXITED(st)) return WEXITSTATUS(st);
    return 1;
}

static int abrir_via_sa(int argc, char **argv, const char *nome_sa)
{
    char sa[PATH_MAX];
    if (caminho_comando_irmao("sa", sa, sizeof(sa)) != 0) {
        fprintf(stderr, "atualizar-manual-funcional: não foi possível localizar o comando sa.\n");
        return 1;
    }

    char **sargs = calloc((size_t)argc + 4, sizeof(char *));
    if (!sargs) return 1;

    int pos = 0;
    sargs[pos++] = sa;
    sargs[pos++] = (char *)nome_sa;
    for (int i = 1; i < argc; i++) {
        if (arg_ignorado_no_repasse(argv[i])) continue;
        sargs[pos++] = argv[i];
    }
    sargs[pos] = NULL;

    execv(sa, sargs);
    perror("atualizar-manual-funcional: execv sa");
    free(sargs);
    return 127;
}

int main(int argc, char *argv[])
{
    for (int i = 1; i < argc; i++) {
        if (eh_ajuda(argv[i])) { ajuda(); return 0; }
    }

    char raiz_sisc[PATH_MAX];
    if (localizar_raiz_sisc(raiz_sisc, sizeof(raiz_sisc)) != 0) {
        fprintf(stderr, "atualizar-manual-funcional: não foi possível localizar a raiz sisc.\n");
        return 1;
    }

    char sistema_alvo[PATH_MAX];
    detectar_sistema_alvo(raiz_sisc, argc, argv, sistema_alvo, sizeof(sistema_alvo));

    char json_path[PATH_MAX * 2];
    snprintf(json_path, sizeof(json_path), "%s/arvores/operador-manual-funcional.json", raiz_sisc);

    int rc = gerar_mapa_funcional(argc, argv, json_path, sistema_alvo);
    if (rc != 0) return rc;

    printf("Operador manual funcional atualizado: %s\n", json_path);
    return abrir_via_sa(argc, argv, json_path);
}
