/*
 * deletar-arvores - remove interativamente uma arvore criada por pp --sa
 * Uso: pp --deletar-arvores
 *
 * Percorre recursivamente o sistema atual, identifica arquivos .json que
 * possuem estrutura de árvore --sa (nome, criadoEm, atualizadoEm, filhos),
 * lista-os interativamente e remove o selecionado.
 *
 * Diretórios internos (.git, secretos, espaco, sessoes, tmp, cache, rascunho,
 * etc.) são ignorados na recursão.
 */

#define _GNU_SOURCE
#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <dirent.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <errno.h>
#include "../restricao.h"

typedef struct {
    char rel[PATH_MAX * 2];
    char abs[PATH_MAX * 2];
} Arvore;

static const char *dirs_ignorados[] = {
    ".git", "node_modules", "vendor", "logs", "log",
    "tmp", "cache", "secretos", "sessoes", "espaco",
    "histprompt", "metricas-tokens", ".svn", ".hg",
    "rascunho"
};

static void uso(void)
{
    fputs(
        "Uso:\n"
        "  pp --deletar-arvores\n"
        "  pp --deletar-arvores --ajuda:<grupo>\n"
        "\n"
        "Descrição:\n"
        "  Remove interativamente uma árvore JSON criada por pp --sa.\n"
        "  Percorre recursivamente o sistema atual e só lista/apaga arquivos .json\n"
        "  que contenham a chave única 'tipo': 'arvore-sa' no nível raiz.\n"
        "\n"
        "Grupos de ajuda: uso, processo, riscos, exemplos.\n"
        "\n"
        "1) Uso e ajuda [uso ajuda]\n"
        "  --ajuda, --help, -h            Exibe esta ajuda\n"
        "  --ajuda:<grupo>                Filtra um grupo. Ex: pp --deletar-arvores --ajuda:riscos\n"
        "\n"
        "2) Processo [processo]\n"
        "  Lista de forma enumerada todos os arquivos .json de árvore --sa\n"
        "  encontrados no sistema atual, exibindo o caminho relativo.\n"
        "  O operador digita o número da árvore que deseja deletar.\n"
        "\n"
        "3) Riscos [riscos atencao]\n"
        "  A exclusão é irreversível e não há confirmação adicional além da seleção.\n"
        "\n"
        "4) Exemplos [exemplos]\n"
        "  pp --deletar-arvores\n"
        "  Exemplo com todas as flags do grupo:\n"
        "    pp --deletar-arvores  (interativo: lista, seleciona, remove)\n",
        stdout);
}

static int termina_com(const char *s, const char *suf)
{
    size_t a = strlen(s), b = strlen(suf);
    return a >= b && strcasecmp(s + a - b, suf) == 0;
}

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

static int eh_arquivo_regular_sem_seguir_symlink(const char *path)
{
    struct stat st;
    if (lstat(path, &st) != 0) return 0;
    return S_ISREG(st.st_mode);
}

static int deve_ignorar_dir(const char *nome)
{
    if (nome[0] == '.') return 1;
    size_t n = sizeof(dirs_ignorados) / sizeof(dirs_ignorados[0]);
    for (size_t i = 0; i < n; i++) {
        if (strcmp(nome, dirs_ignorados[i]) == 0) return 1;
    }
    return 0;
}

static int montar_path_abs(char *out, size_t out_sz, const char *dir, const char *nome)
{
    int n = snprintf(out, out_sz, "%s/%s", dir, nome);
    return n >= 0 && (size_t)n < out_sz;
}

static int montar_path_rel(char *out, size_t out_sz, const char *dir_rel, const char *nome)
{
    int n;
    if (dir_rel && *dir_rel) n = snprintf(out, out_sz, "%s/%s", dir_rel, nome);
    else n = snprintf(out, out_sz, "%s", nome);
    return n >= 0 && (size_t)n < out_sz;
}

static int cmp_arvore(const void *a, const void *b)
{
    const Arvore *aa = (const Arvore *)a;
    const Arvore *bb = (const Arvore *)b;
    return strcasecmp(aa->rel, bb->rel);
}

static int adicionar_arvore(Arvore **out, int *total, int *cap, const char *rel, const char *abs)
{
    if (*total >= *cap) {
        int novo_cap = *cap ? *cap * 2 : 32;
        Arvore *nv = realloc(*out, (size_t)novo_cap * sizeof(Arvore));
        if (!nv) return -1;
        *out = nv;
        *cap = novo_cap;
    }
    snprintf((*out)[*total].rel, sizeof((*out)[*total].rel), "%s", rel);
    snprintf((*out)[*total].abs, sizeof((*out)[*total].abs), "%s", abs);
    (*total)++;
    return 0;
}

/*
 * Verifica se o arquivo .json foi criado pelo comando --sa.
 * Procura pela chave única "tipo": "arvore-sa" nas primeiras 2048 bytes.
 * Retorna 1 se é árvore --sa, 0 caso contrário.
 */
static int eh_arvore_sa(const char *path)
{
    FILE *f = fopen(path, "rb");
    if (!f) return 0;

    char buf[2048];
    size_t n = fread(buf, 1, sizeof(buf) - 1, f);
    fclose(f);
    if (n == 0) return 0;
    buf[n] = '\0';

    const char *p = buf;
    while (*p && isspace((unsigned char)*p)) p++;
    if (*p != '{') return 0;

    /* Procura pela chave única: "tipo": "arvore-sa" */
    for (size_t i = 0; i + 17 < n; i++) {
        if (buf[i] == '"' &&
            strncmp(buf + i + 1, "tipo", 4) == 0 && buf[i + 5] == '"') {
            const char *v = buf + i + 6;
            while (v < buf + n && (*v == ' ' || *v == '\t' || *v == '\n' || *v == '\r' || *v == ':')) v++;
            if (v < buf + n && *v == '"') {
                v++;
                if (strncmp(v, "arvore-sa", 9) == 0)
                    return 1;
            }
        }
    }
    return 0;
}

static int listar_jsons_arvore_sa(const char *dir_abs, const char *dir_rel,
                                  Arvore **out, int *total, int *cap)
{
    DIR *d = opendir(dir_abs);
    if (!d) return 0;

    struct dirent *e;
    while ((e = readdir(d)) != NULL) {
        const char *nome = e->d_name;
        if (nome[0] == '.' || !termina_com(nome, ".json")) continue;

        char abs[PATH_MAX * 2];
        char rel[PATH_MAX * 2];
        if (!montar_path_abs(abs, sizeof(abs), dir_abs, nome)) continue;
        if (!eh_arquivo_regular_sem_seguir_symlink(abs)) continue;
        if (!eh_arvore_sa(abs)) continue;
        if (!montar_path_rel(rel, sizeof(rel), dir_rel, nome)) continue;

        if (adicionar_arvore(out, total, cap, rel, abs) != 0) {
            closedir(d);
            return -1;
        }
    }

    closedir(d);
    return 0;
}

static int percorrer_recursivo(const char *dir_abs, const char *dir_rel,
                               Arvore **out, int *total, int *cap)
{
    if (listar_jsons_arvore_sa(dir_abs, dir_rel, out, total, cap) != 0)
        return -1;

    DIR *d = opendir(dir_abs);
    if (!d) return 0;

    struct dirent *e;
    while ((e = readdir(d)) != NULL) {
        const char *nome = e->d_name;
        if (!strcmp(nome, ".") || !strcmp(nome, "..")) continue;
        if (deve_ignorar_dir(nome)) continue;

        char filho_abs[PATH_MAX * 2];
        char filho_rel[PATH_MAX * 2];
        if (!montar_path_abs(filho_abs, sizeof(filho_abs), dir_abs, nome)) continue;
        if (!eh_dir_sem_seguir_symlink(filho_abs)) continue;
        if (!montar_path_rel(filho_rel, sizeof(filho_rel), dir_rel, nome)) continue;

        if (percorrer_recursivo(filho_abs, filho_rel, out, total, cap) != 0) {
            closedir(d);
            return -1;
        }
    }

    closedir(d);
    return 0;
}

static int ler_numero(int total)
{
    char linha[128];
    printf("Digite o numero da arvore a apagar: ");
    fflush(stdout);
    if (!fgets(linha, sizeof(linha), stdin)) return -1;

    char *p = linha;
    while (isspace((unsigned char)*p)) p++;
    if (!isdigit((unsigned char)*p)) return -1;

    char *fim = NULL;
    long n = strtol(p, &fim, 10);
    while (fim && isspace((unsigned char)*fim)) fim++;
    if (!fim || *fim != '\0') return -1;
    return (n >= 1 && n <= total) ? (int)n : -1;
}

int main(int argc, char **argv)
{
    if (restricao_verificar("deletar-arvores") != 0) return 1;

    if (argc > 1) {
        if (!strcmp(argv[1], "--help") || !strcmp(argv[1], "--ajuda") || !strcmp(argv[1], "-h")) {
            uso();
            return 0;
        }
        uso();
        return 1;
    }

    char raiz[PATH_MAX];
    if (!getcwd(raiz, sizeof(raiz))) {
        perror("deletar-arvores: getcwd");
        return 1;
    }

    Arvore *arvores = NULL;
    int total = 0, cap = 0;
    if (percorrer_recursivo(raiz, "", &arvores, &total, &cap) != 0) {
        free(arvores);
        fprintf(stderr, "deletar-arvores: erro de memoria ao listar arvores.\n");
        return 1;
    }

    if (total == 0) {
        free(arvores);
        fprintf(stderr, "deletar-arvores: nenhuma arvore --sa encontrada no sistema atual.\n");
        return 1;
    }

    qsort(arvores, (size_t)total, sizeof(Arvore), cmp_arvore);

    printf("Arvores --sa disponiveis no sistema atual:\n");
    for (int i = 0; i < total; i++) {
        printf("%2d) %s\n", i + 1, arvores[i].rel);
    }

    int esc = ler_numero(total);
    if (esc < 1) {
        fprintf(stderr, "deletar-arvores: numero invalido. Nenhuma arvore foi apagada.\n");
        free(arvores);
        return 1;
    }

    Arvore *sel = &arvores[esc - 1];
    if (unlink(sel->abs) != 0) {
        fprintf(stderr, "deletar-arvores: nao foi possivel apagar %s: %s\n", sel->rel, strerror(errno));
        free(arvores);
        return 1;
    }

    printf("[apagada] %s\n", sel->rel);
    free(arvores);
    return 0;
}
