/*
 * deletar-conta-llm - remove interativamente uma conta LLM e secretos nao compartilhados
 * Uso: pp --deletar-conta-llm
 */

#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 "../restricao.h"

typedef struct { char nome[PATH_MAX]; char arquivo[PATH_MAX]; char caminho[PATH_MAX]; } Conta;

typedef struct { char itens[8][PATH_MAX]; int total; } Segredos;

static void uso(void)
{
    fputs(
        "Uso:\n"
        "  pp --deletar-conta-llm\n"
        "  pp --deletar-conta-llm --ajuda:<grupo>\n"
        "\n"
        "Descrição:\n"
        "  Remove interativamente uma conta LLM e os segredos vinculados que não sejam\n"
        "  compartilhados por outras contas.\n"
        "\n"
        "Grupos de ajuda: uso, processo, secretos, 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-conta-llm --ajuda:secretos\n"
        "\n"
        "2) Processo [processo]\n"
        "  Lista contas-llm/*.json exceto llm.json, solicita seleção e remove o preset.\n"
        "\n"
        "3) Secretos [secretos arquivos]\n"
        "  Remove apiKey em secretos/*.txt ou OAuth em secretos/*.json apenas quando\n"
        "  não forem referenciados por outras contas.\n"
        "\n"
        "4) Exemplos [exemplos]\n"
        "  pp --deletar-conta-llm\n"
        "  Exemplo com todas as flags do grupo:\n"
        "    pp --deletar-conta-llm  (interativo: lista, seleciona, remove conta e secretos)\n",
        stdout);
}

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

static void resolver_dir(const char *raiz, const char *nome, char *out, size_t tam)
{
    char direto[PATH_MAX * 2], compat[PATH_MAX * 2];
    snprintf(direto, sizeof(direto), "%s/%s", raiz, nome);
    if (eh_dir(direto) || strcmp(nome, "contas-llm") == 0) { snprintf(out, tam, "%s", direto); return; }
    snprintf(compat, sizeof(compat), "%s/siscore/%s", raiz, nome);
    if (eh_dir(compat)) { snprintf(out, tam, "%s", compat); return; }
    snprintf(out, tam, "%s", direto);
}

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

static int cmp_conta(const void *a, const void *b)
{
    const Conta *ca = (const Conta *)a, *cb = (const Conta *)b;
    return strcasecmp(ca->nome, cb->nome);
}

static int listar_contas(const char *dir_contas, Conta **out, int *total_out)
{
    DIR *d = opendir(dir_contas);
    if (!d) return -1;
    int cap = 32, total = 0;
    Conta *v = calloc((size_t)cap, sizeof(Conta));
    if (!v) { closedir(d); return -1; }
    struct dirent *e;
    while ((e = readdir(d))) {
        const char *n = e->d_name;
        if (n[0] == '.' || strcmp(n, "llm.json") == 0 || !termina_com(n, ".json")) continue;
        char path[PATH_MAX * 2]; snprintf(path, sizeof(path), "%s/%s", dir_contas, n);
        struct stat st; if (stat(path, &st) != 0 || !S_ISREG(st.st_mode)) continue;
        if (total >= cap) { cap *= 2; Conta *nv = realloc(v, (size_t)cap * sizeof(Conta)); if (!nv) { free(v); closedir(d); return -1; } v = nv; }
        snprintf(v[total].arquivo, sizeof(v[total].arquivo), "%s", n);
        snprintf(v[total].caminho, sizeof(v[total].caminho), "%s", path);
        snprintf(v[total].nome, sizeof(v[total].nome), "%s", n);
        v[total].nome[strlen(v[total].nome) - 5] = '\0';
        total++;
    }
    closedir(d);
    qsort(v, (size_t)total, sizeof(Conta), cmp_conta);
    *out = v; *total_out = total; return 0;
}

static char *ler_arquivo(const char *p)
{
    FILE *fp = fopen(p, "rb"); if (!fp) return NULL;
    fseek(fp, 0, SEEK_END); long t = ftell(fp); if (t < 0 || t > 20 * 1024 * 1024) { fclose(fp); return NULL; }
    fseek(fp, 0, SEEK_SET); char *b = malloc((size_t)t + 1); if (!b) { fclose(fp); return NULL; }
    size_t n = fread(b, 1, (size_t)t, fp); fclose(fp); b[n] = '\0'; return b;
}

static char *json_get_string(const char *json, const char *key)
{
    char pat[128]; snprintf(pat, sizeof(pat), "\"%s\"", key);
    const char *p = strstr(json, pat); if (!p) return NULL;
    p = strchr(p + strlen(pat), ':'); if (!p) return NULL; p++;
    while (*p && isspace((unsigned char)*p)) p++;
    if (*p != '"') return NULL; p++;
    char *out = malloc(strlen(p) + 1); if (!out) return NULL;
    size_t j = 0;
    while (*p && *p != '"') {
        if (*p == '\\' && p[1]) p++;
        out[j++] = *p++;
    }
    out[j] = '\0';
    return out;
}

static int nome_seguro(const char *s)
{
    if (!s || !*s || strstr(s, "..") || strchr(s, '/') || strchr(s, '\\')) return 0;
    for (const char *p = s; *p; p++) if (!(isalnum((unsigned char)*p) || *p == '.' || *p == '_' || *p == '-')) return 0;
    return 1;
}

static void seg_add(Segredos *s, const char *nome, const char *ext)
{
    if (!nome_seguro(nome) || s->total >= 8) return;
    char arq[PATH_MAX];
    if (termina_com(nome, ".txt") || termina_com(nome, ".json")) snprintf(arq, sizeof(arq), "%s", nome);
    else snprintf(arq, sizeof(arq), "%s%s", nome, ext);
    for (int i = 0; i < s->total; i++) if (strcmp(s->itens[i], arq) == 0) return;
    snprintf(s->itens[s->total++], PATH_MAX, "%s", arq);
}

static Segredos segredos_conta(const char *path)
{
    Segredos s; memset(&s, 0, sizeof(s));
    char *json = ler_arquivo(path); if (!json) return s;
    char *tipo = json_get_string(json, "tipo");
    char *apiKey = json_get_string(json, "apiKey");
    char *arquivo = json_get_string(json, "arquivo");
    char *conexao = json_get_string(json, "conexao");
    if (apiKey) seg_add(&s, apiKey, ".txt");
    if (arquivo) seg_add(&s, arquivo, ".json");
    if (!apiKey && tipo && strcmp(tipo, "key") == 0 && conexao) seg_add(&s, conexao, ".txt");
    free(tipo); free(apiKey); free(arquivo); free(conexao); free(json);
    return s;
}

static int usa_segredo(const char *path, const char *seg)
{
    Segredos s = segredos_conta(path);
    for (int i = 0; i < s.total; i++) if (strcmp(s.itens[i], seg) == 0) return 1;
    return 0;
}

static int ler_numero(int total)
{
    char linha[64]; printf("Digite o numero da conta 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;
    int n = atoi(p); return (n >= 1 && n <= total) ? n : -1;
}

int main(int argc, char **argv)
{     if (restricao_verificar("deletar-conta-llm") != 0) return 1; 
    if (argc > 1) { if (argc == 2 && (!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("getcwd"); return 1; }
    char dir_contas[PATH_MAX * 2], dir_secretos[PATH_MAX * 2];
    resolver_dir(raiz, "contas-llm", dir_contas, sizeof(dir_contas));
    resolver_dir(raiz, "secretos", dir_secretos, sizeof(dir_secretos));
    Conta *contas = NULL; int total = 0;
    if (listar_contas(dir_contas, &contas, &total) != 0) { fprintf(stderr, "deletar-conta-llm: diretorio nao encontrado: contas-llm\n"); return 1; }
    if (total == 0) { fprintf(stderr, "deletar-conta-llm: nenhuma conta encontrada em contas-llm/.\n"); free(contas); return 1; }
    printf("Contas LLM disponiveis:\n"); for (int i = 0; i < total; i++) printf("%2d) %s\n", i + 1, contas[i].nome);
    int esc = ler_numero(total); if (esc < 1) { fprintf(stderr, "deletar-conta-llm: numero invalido.\n"); free(contas); return 1; }
    Conta sel = contas[esc - 1]; Segredos segs = segredos_conta(sel.caminho);
    if (unlink(sel.caminho) != 0) { fprintf(stderr, "deletar-conta-llm: nao foi possivel apagar contas-llm/%s\n", sel.arquivo); free(contas); return 1; }
    printf("[apagada] contas-llm/%s\n", sel.arquivo);
    if (segs.total == 0) printf("Nenhum secreto vinculado encontrado na conta apagada.\n");
    for (int i = 0; i < segs.total; i++) {
        int usado = 0; char usuarios[4096] = "";
        for (int j = 0; j < total; j++) {
            if (strcmp(contas[j].arquivo, sel.arquivo) == 0) continue;
            if (usa_segredo(contas[j].caminho, segs.itens[i])) { if (usuarios[0]) strncat(usuarios, ", ", sizeof(usuarios)-strlen(usuarios)-1); strncat(usuarios, contas[j].arquivo, sizeof(usuarios)-strlen(usuarios)-1); usado = 1; }
        }
        char llm[PATH_MAX * 2]; snprintf(llm, sizeof(llm), "%s/llm.json", dir_contas);
        if (access(llm, F_OK) == 0 && usa_segredo(llm, segs.itens[i])) { if (usuarios[0]) strncat(usuarios, ", ", sizeof(usuarios)-strlen(usuarios)-1); strncat(usuarios, "llm.json", sizeof(usuarios)-strlen(usuarios)-1); usado = 1; }
        if (usado) { printf("[preservado] secretos/%s usado por: %s\n", segs.itens[i], usuarios); continue; }
        char sp[PATH_MAX * 2]; snprintf(sp, sizeof(sp), "%s/%s", dir_secretos, segs.itens[i]);
        if (access(sp, F_OK) != 0) { printf("[nao encontrado] secretos/%s\n", segs.itens[i]); continue; }
        if (unlink(sp) != 0) { fprintf(stderr, "deletar-conta-llm: conta apagada, mas nao foi possivel apagar secretos/%s\n", segs.itens[i]); free(contas); return 1; }
        printf("[apagado] secretos/%s\n", segs.itens[i]);
    }
    printf("Exclusao de conta LLM concluida.\n");
    free(contas);
    return 0;
}
