/*
 * listar-contas-llm - Lista contas LLM nos JSONs de contas-llm/
 * Uso: pp --listar-contas-llm[=xxx]
 *
 * Sem argumento: lista todas as contas em ordem alfabética.
 * Com argumento: filtra contas cujo nome contenha 'xxx'.
 * Ignora llm.json.
 */

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

#define ANSI_LARANJA_BRILHANTE "\033[1;38;5;214m"
#define ANSI_RESET "\033[0m"

static void uso(void)
{
    fputs(
        "Uso:\n"
        "  pp --listar-contas-llm[=<filtro>]\n"
        "  pp --listar-contas-llm <filtro>\n"
        "  pp --listar-contas-llm --ajuda:<grupo>\n"
        "\n"
        "Descrição:\n"
        "  Lista contas LLM disponíveis no sistema atual, com filtro opcional por trecho.\n"
        "\n"
        "Grupos de ajuda: uso, filtro, comportamento, exemplos.\n"
        "\n"
        "1) Uso e ajuda [uso ajuda]\n"
        "  --ajuda, --help, -h            Exibe esta ajuda\n"
        "  --ajuda:<grupo>                Filtra um grupo. Ex: pp --listar-contas-llm --ajuda:filtro\n"
        "\n"
        "2) Filtro [filtro entrada]\n"
        "  =<filtro>                      Filtra pelo trecho informado\n"
        "  <filtro>                       Forma alternativa como argumento separado\n"
        "  Sem filtro                     Lista todos os itens\n"
        "  Exemplo com todas as flags do grupo:\n"
        "    pp --listar-contas-llm=gpt  ou  pp --listar-contas-llm gpt\n"
        "\n"
        "3) Comportamento [comportamento]\n"
        "  Ordena os resultados alfabeticamente. A busca por trecho é case-insensitive\n"
        "  quando suportada pelo comando.\n"
        "\n"
        "4) Exemplos [exemplos]\n"
        "  pp --listar-contas-llm\n"
        "  pp --listar-contas-llm=gpt\n"
        "  pp --listar-contas-llm gpt\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 cmp_str(const void *a, const void *b)
{
    return strcasecmp(*(const char *const *)a, *(const char *const *)b);
}

static int nome_contem(const char *nome, const char *filtro)
{
    if (!filtro || !*filtro) return 1;
    return !!strcasestr(nome, filtro);
}

static char *ler_arquivo(const char *caminho, size_t *tam_out)
{
    FILE *fp = fopen(caminho, "rb");
    if (!fp) return NULL;
    if (fseek(fp, 0, SEEK_END) != 0) { fclose(fp); return NULL; }
    long tam = ftell(fp);
    if (tam < 0 || tam > 20 * 1024 * 1024) { fclose(fp); return NULL; }
    if (fseek(fp, 0, SEEK_SET) != 0) { fclose(fp); return NULL; }

    char *buf = malloc((size_t)tam + 1);
    if (!buf) { fclose(fp); return NULL; }
    size_t lido = fread(buf, 1, (size_t)tam, fp);
    fclose(fp);
    buf[lido] = '\0';
    if (tam_out) *tam_out = lido;
    return buf;
}

static size_t aparar_espaco_final(const char *s, size_t tam)
{
    while (tam > 0 && isspace((unsigned char)s[tam - 1])) tam--;
    return tam;
}

static int conteudos_equivalentes(const char *a, size_t tam_a, const char *b, size_t tam_b)
{
    tam_a = aparar_espaco_final(a, tam_a);
    tam_b = aparar_espaco_final(b, tam_b);
    return tam_a == tam_b && memcmp(a, b, tam_a) == 0;
}

static int arquivo_equivale_ativo(const char *caminho, const char *ativo, size_t tam_ativo)
{
    if (!ativo) return 0;
    size_t tam = 0;
    char *conteudo = ler_arquivo(caminho, &tam);
    if (!conteudo) return 0;
    int igual = conteudos_equivalentes(conteudo, tam, ativo, tam_ativo);
    free(conteudo);
    return igual;
}

static void resolver_dir(const char *raiz, const char *nome, char *out, size_t tam)
{
    char direto[PATH_MAX * 2];
    snprintf(direto, sizeof(direto), "%s/%s", raiz, nome);
    snprintf(out, tam, "%s", direto);
}

int main(int argc, char **argv)
{     if (restricao_verificar("listar-contas-llm") != 0) return 1; 
    const char *filtro = "";

    for (int i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "--help") || !strcmp(argv[i], "--ajuda") || !strcmp(argv[i], "-h")) {
            uso();
            return 0;
        }
        if (argv[i][0] != '-' && !filtro[0]) {
            filtro = argv[i];
            continue;
        }
        uso();
        return 1;
    }

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

    char dir[PATH_MAX * 2];
    resolver_dir(raiz, "contas-llm", dir, sizeof(dir));

    DIR *d = opendir(dir);
    if (!d) {
        fprintf(stderr, "listar-contas-llm: diretorio contas-llm nao encontrado.\n");
        return 1;
    }

    int cap = 32, total = 0;
    char **nomes = malloc((size_t)cap * sizeof(char *));
    if (!nomes) { closedir(d); return 1; }

    struct dirent *e;
    while ((e = readdir(d)) != NULL) {
        const char *n = e->d_name;
        if (!termina_com(n, ".json")) continue;
        if (!strcmp(n, "llm.json")) continue;
        if (!nome_contem(n, filtro)) continue;

        if (total >= cap) {
            cap *= 2;
            char **nv = realloc(nomes, (size_t)cap * sizeof(char *));
            if (!nv) { closedir(d); free(nomes); return 1; }
            nomes = nv;
        }
        nomes[total] = strdup(n);
        if (!nomes[total]) { closedir(d); free(nomes); return 1; }
        total++;
    }
    closedir(d);

    qsort(nomes, (size_t)total, sizeof(char *), cmp_str);

    char caminho_llm[PATH_MAX * 4];
    snprintf(caminho_llm, sizeof(caminho_llm), "%s/llm.json", dir);
    size_t tam_ativo = 0;
    char *ativo = ler_arquivo(caminho_llm, &tam_ativo);

    for (int i = 0; i < total; i++) {
        char caminho_conta[PATH_MAX * 4];
        snprintf(caminho_conta, sizeof(caminho_conta), "%s/%s", dir, nomes[i]);
        if (arquivo_equivale_ativo(caminho_conta, ativo, tam_ativo)) {
            printf("%sem uso%s %s\n", ANSI_LARANJA_BRILHANTE, ANSI_RESET, nomes[i]);
        } else {
            printf("%s\n", nomes[i]);
        }
        free(nomes[i]);
    }
    free(ativo);
    free(nomes);

    if (total == 0) {
        printf("Nenhuma conta LLM encontrada");
        if (filtro && *filtro) printf(" com '%s'", filtro);
        printf(".\n");
    }

    return 0;
}
