/*
 * clone-gitprog - Clona o kit publico gitprog para o diretorio atual.
 * Uso:
 *   pp --clone-gitprog [--limpar]
 *
 * O repositorio gitprog e publico: https://github.com/jrcostarrear/gitprog.git
 * O clone e feito dentro da pasta onde o comando e invocado (git clone ... .).
 * Com --limpar, o conteudo do diretorio atual e removido antes do clone.
 * Por seguranca, --limpar recusa limpar "/" ou qualquer pasta dentro da
 * instalacao SISC (raiz derivada do executavel).
 */

#define _DEFAULT_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <ctype.h>
#include <dirent.h>
#include <errno.h>
#include <unistd.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/wait.h>

#define GITPROG_URL "https://github.com/jrcostarrear/gitprog.git"

static void uso(void)
{
    fputs(
        "Uso:\n"
        "  pp --clone-gitprog [--limpar]\n"
        "  pp --clone-gitprog --ajuda:<grupo>\n"
        "\n"
        "Descrição:\n"
        "  Clona o kit público gitprog para o diretório atual, deixando o\n"
        "  conteúdo do repositório diretamente na pasta de execução.\n"
        "\n"
        "Grupos de ajuda: uso, entrada, opcoes, processo, seguranca, exemplos.\n"
        "\n"
        "1) Uso e ajuda [uso ajuda]\n"
        "  --ajuda, --help, -h            Exibe esta ajuda\n"
        "  --ajuda:<grupo>                Filtra um grupo. Ex: pp --clone-gitprog --ajuda:seguranca\n"
        "\n"
        "2) Entrada [entrada]\n"
        "  Nenhuma entrada obrigatória: a conta e o repositório são fixos.\n"
        "  Fonte: https://github.com/jrcostarrear/gitprog.git (público).\n"
        "\n"
        "3) Opções [opcoes]\n"
        "  --limpar                       Remove o conteúdo da pasta atual antes do clone\n"
        "\n"
        "4) Processo [processo]\n"
        "  Executa git clone <url> . na pasta onde o comando é invocado.\n"
        "  O repositório é público, portanto não exige chave SSH nem conta.\n"
        "\n"
        "5) Segurança [seguranca]\n"
        "  Sem --limpar, o clone só funciona em pasta vazia (regra do git clone .).\n"
        "  Com --limpar, recusa limpar '/' e qualquer pasta dentro da instalação SISC.\n"
        "\n"
        "6) Exemplos [exemplos]\n"
        "  mkdir -p /tmp/meu-kit && cd /tmp/meu-kit && pp --clone-gitprog\n"
        "  mkdir -p /tmp/meu-kit && cd /tmp/meu-kit && pp --clone-gitprog --limpar\n",
        stdout);
}

static int raiz_sisc_por_executavel(char *out, size_t tam)
{
    char exe[PATH_MAX];
    ssize_t n = readlink("/proc/self/exe", exe, sizeof(exe) - 1);
    if (n <= 0) return -1;
    exe[n] = '\0';
    for (int i = 0; i < 3; i++) {
        char *slash = strrchr(exe, '/');
        if (!slash) return -1;
        *slash = '\0';
    }
    snprintf(out, tam, "%s", exe);
    return 0;
}

static int remover_recursivo(const char *path)
{
    struct stat st;
    if (lstat(path, &st) != 0) return errno == ENOENT ? 0 : -1;
    if (S_ISDIR(st.st_mode)) {
        DIR *d = opendir(path);
        if (!d) return -1;
        struct dirent *e;
        int rc = 0;
        while ((e = readdir(d))) {
            if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
            char filho[PATH_MAX * 2];
            snprintf(filho, sizeof(filho), "%s/%s", path, e->d_name);
            if (remover_recursivo(filho) != 0) rc = -1;
        }
        closedir(d);
        if (rmdir(path) != 0) rc = -1;
        return rc;
    }
    return unlink(path);
}

static int limpar_diretorio(const char *cwd)
{
    DIR *d = opendir(cwd);
    if (!d) return -1;
    struct dirent *e;
    int rc = 0;
    while ((e = readdir(d))) {
        if (!strcmp(e->d_name, ".") || !strcmp(e->d_name, "..")) continue;
        char path[PATH_MAX * 2];
        snprintf(path, sizeof(path), "%s/%s", cwd, e->d_name);
        if (remover_recursivo(path) != 0) rc = -1;
    }
    closedir(d);
    return rc;
}

static int limpar_seguro(const char *cwd)
{
    if (!cwd || !*cwd) return -1;
    if (strcmp(cwd, "/") == 0) {
        fprintf(stderr, "clone-gitprog: recusado limpar a raiz '/'.\n");
        return -1;
    }

    char raiz[PATH_MAX];
    if (raiz_sisc_por_executavel(raiz, sizeof(raiz)) == 0) {
        char real_cwd[PATH_MAX], real_raiz[PATH_MAX];
        if (realpath(cwd, real_cwd) && realpath(raiz, real_raiz)) {
            size_t len = strlen(real_raiz);
            if (strcmp(real_cwd, real_raiz) == 0 ||
                (strncmp(real_cwd, real_raiz, len) == 0 && real_cwd[len] == '/')) {
                fprintf(stderr, "clone-gitprog: recusado limpar dentro da instalação SISC: %s\n", cwd);
                return -1;
            }
        }
    }

    return limpar_diretorio(cwd);
}

static int run_cmd(char *const argv[], const char *cwd)
{
    pid_t pid = fork();
    if (pid < 0) return -1;
    if (pid == 0) {
        if (cwd && chdir(cwd) != 0) _exit(127);
        execvp(argv[0], argv);
        perror(argv[0]);
        _exit(127);
    }
    int status = 0;
    if (waitpid(pid, &status, 0) < 0) return -1;
    if (WIFEXITED(status)) return WEXITSTATUS(status);
    return -1;
}

int main(int argc, char *argv[])
{
    int limpar = 0;
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "--ajuda") == 0 || strcmp(argv[i], "--help") == 0 || strcmp(argv[i], "-h") == 0) {
            uso();
            return 0;
        }
        if (strcmp(argv[i], "--limpar") == 0) {
            limpar = 1;
        } else {
            uso();
            return 1;
        }
    }

    char cwd[PATH_MAX];
    if (!getcwd(cwd, sizeof(cwd))) {
        fprintf(stderr, "clone-gitprog: não foi possível detectar a pasta atual.\n");
        return 1;
    }

    if (limpar) {
        printf("clone-gitprog: limpando conteúdo de %s ...\n", cwd);
        fflush(stdout);
        if (limpar_seguro(cwd) != 0) {
            fprintf(stderr, "clone-gitprog: falha ao limpar %s\n", cwd);
            return 1;
        }
    }

    printf("clone-gitprog: clonando %s em %s ...\n", GITPROG_URL, cwd);
    fflush(stdout);
    char *args[] = { "git", "clone", GITPROG_URL, ".", NULL };
    int rc = run_cmd(args, cwd);
    if (rc != 0) {
        fprintf(stderr, "clone-gitprog: git clone falhou (código %d).\n", rc);
        return rc ? rc : 1;
    }

    printf("clone-gitprog: kit gitprog clonado em %s\n", cwd);
    return 0;
}
