/*
 * setar-conta-llm - Seleciona interativamente a conta LLM padrão
 * Uso: pp --setar-conta-llm
 *
 * Lista os presets JSON em contas-llm/ (exceto llm.json)
 * e copia o JSON escolhido para contas-llm/llm.json.
 */

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

typedef struct {
    char *nome;      /* sem .json */
    char *arquivo;   /* com .json */
    char *caminho;   /* absoluto */
} Conta;

static int raiz_projeto(char *raiz, size_t tam)
{
    /* Cada comando trata o diretório de execução como raiz do sistema. */
    return getcwd(raiz, tam) ? 0 : -1;
}

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

static int resolver_dir_contas(const char *raiz, char *dir_contas, size_t tam)
{
    char candidato[PATH_MAX * 4];
    snprintf(candidato, sizeof(candidato), "%s/contas-llm", raiz);
    snprintf(dir_contas, tam, "%s", candidato);
    return eh_diretorio(candidato) ? 0 : -1;
}

static int termina_com(const char *s, const char *sufixo)
{
    size_t ls = strlen(s), lf = strlen(sufixo);
    return ls >= lf && strcmp(s + ls - lf, sufixo) == 0;
}

static char *sem_ext_json(const char *arquivo)
{
    size_t len = strlen(arquivo);
    if (len >= 5 && strcmp(arquivo + len - 5, ".json") == 0) len -= 5;
    char *out = malloc(len + 1);
    if (!out) return NULL;
    memcpy(out, arquivo, len);
    out[len] = '\0';
    return out;
}

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

static void liberar_contas(Conta *contas, int total)
{
    if (!contas) return;
    for (int i = 0; i < total; i++) {
        free(contas[i].nome);
        free(contas[i].arquivo);
        free(contas[i].caminho);
    }
    free(contas);
}

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

    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 int escrever_arquivo(const char *caminho, const char *conteudo, size_t tam)
{
    FILE *fp = fopen(caminho, "wb");
    if (!fp) return -1;
    size_t n = fwrite(conteudo, 1, tam, fp);
    if (tam == 0 || conteudo[tam - 1] != '\n') fputc('\n', fp);
    fclose(fp);
    return n == tam ? 0 : -1;
}

static int listar_contas(const char *dir_contas, Conta **out, int *total_out)
{
    DIR *dir = opendir(dir_contas);
    if (!dir) return -1;

    int cap = 32, total = 0;
    Conta *contas = calloc((size_t)cap, sizeof(Conta));
    if (!contas) { closedir(dir); return -1; }

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

        size_t caminho_len = strlen(dir_contas) + strlen(nome) + 2;
        char *caminho = malloc(caminho_len);
        if (!caminho) { liberar_contas(contas, total); closedir(dir); return -1; }
        snprintf(caminho, caminho_len, "%s/%s", dir_contas, nome);

        struct stat st;
        if (stat(caminho, &st) != 0 || !S_ISREG(st.st_mode)) { free(caminho); continue; }

        if (total >= cap) {
            cap *= 2;
            Conta *novo = realloc(contas, (size_t)cap * sizeof(Conta));
            if (!novo) { liberar_contas(contas, total); closedir(dir); return -1; }
            contas = novo;
        }

        contas[total].arquivo = strdup(nome);
        contas[total].nome = sem_ext_json(nome);
        contas[total].caminho = caminho;
        if (!contas[total].arquivo || !contas[total].nome || !contas[total].caminho) {
            liberar_contas(contas, total + 1);
            closedir(dir);
            return -1;
        }
        total++;
    }

    closedir(dir);
    qsort(contas, (size_t)total, sizeof(Conta), cmp_conta);
    *out = contas;
    *total_out = total;
    return 0;
}

static int ler_numero(void)
{
    char linha[128];
    printf("Digite o número da conta: ");
    fflush(stdout);
    if (!fgets(linha, sizeof(linha), stdin)) return -1;

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

static void uso(void)
{
    fputs(
        "Uso:\n"
        "  pp --setar-conta-llm\n"
        "  pp --setar-conta-llm --ajuda:<grupo>\n"
        "\n"
        "Descrição:\n"
        "  Seleciona interativamente a conta LLM padrão do sistema, copiando o preset\n"
        "  escolhido para contas-llm/llm.json.\n"
        "\n"
        "Grupos de ajuda: uso, processo, arquivos, exemplos.\n"
        "\n"
        "1) Uso e ajuda [uso ajuda]\n"
        "  --ajuda, --help, -h            Exibe esta ajuda\n"
        "  --ajuda:<grupo>                Filtra um grupo. Ex: pp --setar-conta-llm --ajuda:arquivos\n"
        "\n"
        "2) Processo [processo]\n"
        "  Lista presets em contas-llm/*.json exceto llm.json, solicita seleção e copia\n"
        "  o conteúdo para llm.json.\n"
        "\n"
        "3) Arquivos [arquivos]\n"
        "  contas-llm/llm.json é lido por parallm, ler-web e outros comandos LLM.\n"
        "\n"
        "4) Exemplos [exemplos]\n"
        "  pp --setar-conta-llm\n"
        "  Exemplo com todas as flags do grupo:\n"
        "    pp --setar-conta-llm  (interativo: lista, seleciona, copia preset para llm.json)\n",
        stdout);
}

int main(int argc, char *argv[])
{     if (restricao_verificar("setar-conta-llm") != 0) return 1; 
    if (argc > 1) {
        if (strcmp(argv[1], "--ajuda") == 0 || strcmp(argv[1], "-h") == 0) {
            uso();
            return 0;
        }
        uso();
        return 1;
    }

    char raiz[PATH_MAX];
    if (raiz_projeto(raiz, sizeof(raiz)) != 0) {
        fprintf(stderr, "setar-conta-llm: não foi possível detectar a raiz do projeto.\n");
        return 1;
    }

    char dir_contas[PATH_MAX * 4];
    if (resolver_dir_contas(raiz, dir_contas, sizeof(dir_contas)) != 0) {
        fprintf(stderr, "setar-conta-llm: diretório contas-llm não encontrado na raiz atual.\n");
        return 1;
    }

    Conta *contas = NULL;
    int total = 0;
    if (listar_contas(dir_contas, &contas, &total) != 0) {
        fprintf(stderr, "setar-conta-llm: erro ao listar %s: %s\n", dir_contas, strerror(errno));
        return 1;
    }

    if (total == 0) {
        fprintf(stderr, "setar-conta-llm: nenhuma conta encontrada em contas-llm/.\n");
        liberar_contas(contas, total);
        return 1;
    }

    printf("Contas LLM disponíveis:\n");
    for (int i = 0; i < total; i++) {
        printf("%2d) %s\n", i + 1, contas[i].nome);
    }

    int escolha = ler_numero();
    if (escolha < 1 || escolha > total) {
        fprintf(stderr, "setar-conta-llm: número inválido.\n");
        liberar_contas(contas, total);
        return 1;
    }

    Conta *sel = &contas[escolha - 1];
    size_t tam = 0;
    char *conteudo = ler_arquivo(sel->caminho, &tam);
    if (!conteudo) {
        fprintf(stderr, "setar-conta-llm: não foi possível ler %s\n", sel->caminho);
        liberar_contas(contas, total);
        return 1;
    }

    size_t caminho_llm_len = strlen(dir_contas) + strlen("/llm.json") + 1;
    char *caminho_llm = malloc(caminho_llm_len);
    if (!caminho_llm) {
        free(conteudo);
        liberar_contas(contas, total);
        return 1;
    }
    snprintf(caminho_llm, caminho_llm_len, "%s/llm.json", dir_contas);
    if (escrever_arquivo(caminho_llm, conteudo, tam) != 0) {
        fprintf(stderr, "setar-conta-llm: não foi possível atualizar %s\n", caminho_llm);
        free(caminho_llm);
        free(conteudo);
        liberar_contas(contas, total);
        return 1;
    }
    free(caminho_llm);

    printf("Conta LLM ativa: %s\n", sel->nome);
    printf("Atualizado: contas-llm/llm.json\n");

    free(conteudo);
    liberar_contas(contas, total);
    return 0;
}
