/*
 * excluir-conector - exclui um conector do modo operacional, mantendo-o na biblioteca
 * Uso: pp --excluir-conector=<nome> [--purge-vestigios] [--sem-backup] [--sim]
 *      pp --excluir-conector <nome>
 *
 * Remove do sistema atual:
 *   - conectores/<nome>/
 *   - web-api/catalogo-<nome>.json
 * e regenera web-api/catalogo-mensagens.json.
 * O pacote central core/biblioteca-conectores/<nome>.tar.gz é preservado
 * (o conector fica guardado na biblioteca e pode ser reimportado).
 * Sem pacote na biblioteca, a exclusão exige --sem-backup.
 */

#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"

static void uso(void) {
    fputs(
        "Uso:\n"
        "  pp --excluir-conector=<nome> [--purge-vestigios] [--sem-backup] [--sim]\n"
        "  pp --excluir-conector <nome>\n"
        "\n"
        "Descrição:\n"
        "  Exclui um conector do modo operacional do sistema atual, mantendo-o\n"
        "  guardado na biblioteca central. Remove conectores/<nome>/ e\n"
        "  web-api/catalogo-<nome>.json e regenera web-api/catalogo-mensagens.json.\n"
        "  O pacote core/biblioteca-conectores/<nome>.tar.gz é preservado e o\n"
        "  conector pode ser reinstalado com pp --importar-conectores.\n"
        "\n"
        "Segurança:\n"
        "  Sem pacote correspondente na biblioteca, a exclusão é recusada, pois\n"
        "  os arquivos seriam perdidos. Use --sem-backup para excluir mesmo assim.\n"
        "  --purge-vestigios também limpa referências do espaco do sistema atual.\n"
        "  --sim pula a confirmação interativa.\n"
        "\n"
        "Exemplos:\n"
        "  pp --excluir-conector=conector-tabela-fipe\n"
        "  pp --excluir-conector conector-email --purge-vestigios\n",
        stdout);
}

static int nome_valido(const char *nome) {
    if (!nome || strncmp(nome, "conector-", 9) != 0 || strlen(nome) > 128) return 0;
    if (strstr(nome, "..")) return 0;
    for (const char *p = nome; *p; p++)
        if (!((*p >= 'a' && *p <= 'z') || (*p >= '0' && *p <= '9') || *p == '-')) return 0;
    return 1;
}

static int shell_quote(const char *s, char *out, size_t outsz) {
    size_t n = 0;
    if (n + 1 >= outsz) return -1;
    out[n++] = '\'';
    for (const char *p = s ? s : ""; *p; p++) {
        if (*p == '\'') {
            const char *q = "'\\''";
            for (int i = 0; q[i]; i++) {
                if (n + 1 >= outsz) return -1;
                out[n++] = q[i];
            }
        } else {
            if (n + 1 >= outsz) return -1;
            out[n++] = *p;
        }
    }
    if (n + 2 >= outsz) return -1;
    out[n++] = '\'';
    out[n] = '\0';
    return 0;
}

static void rm_rf(const char *dir) {
    char q[PATH_MAX * 4], cmd[PATH_MAX * 5];
    if (shell_quote(dir, q, sizeof(q)) == 0) {
        snprintf(cmd, sizeof(cmd), "rm -rf %s", q);
        system(cmd);
    }
}

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

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

/* Lista conectores operacionais: subdiretórios conectores/<nome>/ com manifesto. */
static int listar_operacionais(const char *cwd, char nomes[][PATH_MAX], int max) {
    char dir[PATH_MAX * 2];
    snprintf(dir, sizeof(dir), "%s/conectores", cwd);
    DIR *d = opendir(dir);
    if (!d) return 0;
    int total = 0;
    struct dirent *e;
    while ((e = readdir(d)) && total < max) {
        if (e->d_name[0] == '.' || strncmp(e->d_name, "conector-", 9) != 0) continue;
        char sub[PATH_MAX * 3];
        snprintf(sub, sizeof(sub), "%s/%s", dir, e->d_name);
        if (!eh_dir(sub)) continue;
        snprintf(nomes[total], PATH_MAX, "%s", e->d_name);
        total++;
    }
    closedir(d);
    for (int i = 0; i < total; i++)
        for (int j = i + 1; j < total; j++)
            if (strcasecmp(nomes[i], nomes[j]) > 0) {
                char t[PATH_MAX];
                snprintf(t, sizeof(t), "%s", nomes[i]);
                snprintf(nomes[i], PATH_MAX, "%s", nomes[j]);
                snprintf(nomes[j], PATH_MAX, "%s", t);
            }
    return total;
}

int main(int argc, char **argv) {
    if (restricao_verificar("excluir-conector") != 0) return 1;
    const char *nome = NULL;
    int purge_vestigios = 0, sem_backup = 0, sim = 0;
    for (int i = 1; i < argc; i++) {
        if (!strcmp(argv[i], "--ajuda") || !strcmp(argv[i], "--help") || !strcmp(argv[i], "-h")) { uso(); return 0; }
        else if (!strncmp(argv[i], "--excluir-conector=", 19)) { if (argv[i][19]) nome = argv[i] + 19; }
        else if (!strcmp(argv[i], "--purge-vestigios")) purge_vestigios = 1;
        else if (!strcmp(argv[i], "--sem-backup")) sem_backup = 1;
        else if (!strcmp(argv[i], "--sim")) sim = 1;
        else if (argv[i][0] != '-' && !nome) nome = argv[i];
        else { fprintf(stderr, "excluir-conector: argumento inválido: %s\n", argv[i]); uso(); return 1; }
    }

    char raiz_sisc[PATH_MAX];
    if (raiz_sisc_por_executavel(raiz_sisc, sizeof(raiz_sisc)) != 0) {
        fprintf(stderr, "excluir-conector: raiz SISC não localizada.\n");
        return 1;
    }
    char cwd[PATH_MAX];
    if (!getcwd(cwd, sizeof(cwd))) { perror("getcwd"); return 1; }

    char sel_nome[PATH_MAX] = "";
    if (!nome) {
        static char nomes[256][PATH_MAX];
        int total = listar_operacionais(cwd, nomes, 256);
        if (total == 0) {
            fprintf(stderr, "excluir-conector: nenhum conector operacional em conectores/.\n");
            return 1;
        }
        printf("Conectores operacionais em %s/conectores/:\n", cwd);
        for (int i = 0; i < total; i++) printf("%2d) %s\n", i + 1, nomes[i]);
        printf("\nDigite o número do conector a excluir: ");
        fflush(stdout);
        char entrada[64];
        if (!fgets(entrada, sizeof(entrada), stdin)) return 1;
        int n = atoi(entrada);
        if (n < 1 || n > total) {
            fprintf(stderr, "excluir-conector: seleção inválida.\n");
            return 1;
        }
        snprintf(sel_nome, sizeof(sel_nome), "%s", nomes[n - 1]);
        nome = sel_nome;
    }

    if (!nome_valido(nome)) {
        fprintf(stderr, "excluir-conector: nome de conector inválido: %s\n", nome);
        return 1;
    }

    char dir_con[PATH_MAX * 3], cat_mod[PATH_MAX * 3], pacote[PATH_MAX * 3];
    snprintf(dir_con, sizeof(dir_con), "%s/conectores/%s", cwd, nome);
    snprintf(cat_mod, sizeof(cat_mod), "%s/web-api/catalogo-%s.json", cwd, nome);
    snprintf(pacote, sizeof(pacote), "%s/core/biblioteca-conectores/%s.tar.gz", raiz_sisc, nome);

    int tem_dir = eh_dir(dir_con);
    int tem_cat = eh_arquivo(cat_mod);
    int tem_pacote = eh_arquivo(pacote);
    if (!tem_dir && !tem_cat) {
        fprintf(stderr, "excluir-conector: %s não está instalado no sistema atual.\n", nome);
        return 1;
    }
    if (!tem_pacote && !sem_backup) {
        fprintf(stderr, "excluir-conector: sem pacote guardado em core/biblioteca-conectores/%s.tar.gz.\n", nome);
        fprintf(stderr, "excluir-conector: a exclusão apagaria os arquivos sem backup. Use --sem-backup para excluir mesmo assim.\n");
        return 1;
    }

    printf("Excluir do modo operacional (mantido na biblioteca): %s\n", nome);
    if (tem_dir) printf("  remover: conectores/%s/\n", nome);
    if (tem_cat) printf("  remover: web-api/catalogo-%s.json (+ regenerar agregado)\n", nome);
    printf("  manter:  core/biblioteca-conectores/%s.tar.gz%s\n", nome, tem_pacote ? "" : " (AUSENTE --sem-backup ativo)");
    if (purge_vestigios) printf("  limpar:  referências em espaco/\n");
    if (!sim) {
        char resp[16];
        printf("Confirmar exclusão? [s/N]: ");
        fflush(stdout);
        if (!fgets(resp, sizeof(resp), stdin)) return 1;
        if (!(resp[0] == 's' || resp[0] == 'S' || resp[0] == 'y' || resp[0] == 'Y')) {
            printf("Exclusão cancelada.\n");
            return 1;
        }
    }

    int removidos = 0;
    if (tem_dir) { rm_rf(dir_con); printf("  [ok] removido diretório: conectores/%s\n", nome); removidos++; }
    if (tem_cat) {
        if (unlink(cat_mod) == 0) { printf("  [ok] removido catálogo modular: web-api/catalogo-%s.json\n", nome); removidos++; }
        else fprintf(stderr, "  [aviso] falha ao remover catálogo modular: %s\n", cat_mod);
    }

    char qcwd[PATH_MAX * 4], cmd[PATH_MAX * 8];
    if (shell_quote(cwd, qcwd, sizeof(qcwd)) == 0) {
        snprintf(cmd, sizeof(cmd), "cd %s && ../pp --atualizar-catalogo-mensagens >/dev/null 2>&1", qcwd);
        if (system(cmd) == 0) printf("  [ok] catálogo agregado regenerado\n");
        else fprintf(stderr, "  [aviso] não foi possível regenerar o catálogo agregado automaticamente\n");
    }

    if (purge_vestigios) {
        char espaco[PATH_MAX * 3], qesp[PATH_MAX * 4], qnome[PATH_MAX * 4];
        snprintf(espaco, sizeof(espaco), "%s/espaco", cwd);
        if (eh_dir(espaco) && shell_quote(espaco, qesp, sizeof(qesp)) == 0 && shell_quote(nome, qnome, sizeof(qnome)) == 0) {
            snprintf(cmd, sizeof(cmd), "find %s -type f -name '*%s*' -delete 2>/dev/null; grep -RIl -- %s %s 2>/dev/null | xargs -r rm -f; find %s -depth -type d -name '*%s*' -exec rm -rf {} + 2>/dev/null", qesp, nome, qnome, qesp, qesp, nome);
            system(cmd);
            printf("  [ok] vestígios do espaco limpos para: %s\n", nome);
        }
    }

    if (eh_arquivo(pacote)) printf("  [ok] pacote guardado na biblioteca: core/biblioteca-conectores/%s.tar.gz\n", nome);
    else printf("  [aviso] sem pacote na biblioteca (excluído com --sem-backup)\n");

    printf("Exclusão concluída: %s fora do modo operacional (%d artefato(s) removido(s)).\n", nome, removidos);
    return 0;
}
