// SPDX-License-Identifier: GPL-2.0-only
/*
 *  ppm/tests/test_store.c
 *
 *  End-to-end CAS test: build a tarball, hash it, ingest into a fresh
 *  store, assert it lands at sha512/<aa>/<full>/, double-ingest is a
 *  no-op, hash mismatch is rejected.
 *
 *  Copyright (C) 2026 Project Tick
 */

#include <ppm/store.h>
#include <ppm/crypto.h>

#include <archive.h>
#include <archive_entry.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <unistd.h>

#include "util/path.h"

#define CHECK(expr) do {                                            \
    if (!(expr)) {                                                  \
        fprintf(stderr, "FAIL: %s:%d: %s\n", __FILE__, __LINE__, #expr); \
        return 1;                                                   \
    }                                                               \
} while (0)

static int build_tarball(const char *path, const char *entry, const char *body) {
    struct archive *a = archive_write_new();
    if (!a) return -1;
    archive_write_add_filter_gzip(a);
    archive_write_set_format_pax_restricted(a);
    if (archive_write_open_filename(a, path) != ARCHIVE_OK) {
        archive_write_free(a); return -1;
    }
    struct archive_entry *e = archive_entry_new();
    archive_entry_set_pathname(e, entry);
    archive_entry_set_size(e, (la_int64_t)strlen(body));
    archive_entry_set_filetype(e, AE_IFREG);
    archive_entry_set_perm(e, 0644);
    archive_write_header(a, e);
    archive_write_data(a, body, strlen(body));
    archive_entry_free(e);
    archive_write_close(a);
    archive_write_free(a);
    return 0;
}

int main(void) {
    CHECK(ppm_crypto_init() == PPM_OK);

    char tpl[] = "/tmp/ppm-store-XXXXXX";
    char *base = mkdtemp(tpl);
    CHECK(base != NULL);

    char *store_root, *tar_path;
    CHECK(ppm_path_join(base, "store", &store_root) == PPM_OK);
    CHECK(ppm_path_join(base, "pkg.tar.gz", &tar_path) == PPM_OK);
    CHECK(build_tarball(tar_path, "hello.txt", "world") == 0);

    /* Hash the tarball so we know the expected digest. */
    ppm_sha512_t expected;
    CHECK(ppm_sha512_file(tar_path, &expected) == PPM_OK);

    ppm_store_t *s = NULL;
    CHECK(ppm_store_open(store_root, &s) == PPM_OK);

    CHECK(!ppm_store_has(s, &expected));
    CHECK(ppm_store_ingest_tarball(s, tar_path, &expected) == PPM_OK);
    CHECK(ppm_store_has(s, &expected));

    /* The materialised payload contains the original file. */
    char *obj_path = NULL;
    CHECK(ppm_store_path(s, &expected, &obj_path) == PPM_OK);
    char *file_in_store;
    CHECK(ppm_path_join(obj_path, "hello.txt", &file_in_store) == PPM_OK);
    FILE *f = fopen(file_in_store, "r");
    CHECK(f != NULL);
    char buf[16] = {0};
    size_t n = fread(buf, 1, sizeof(buf) - 1, f);
    fclose(f);
    CHECK(n == 5 && strcmp(buf, "world") == 0);

    /* Re-ingest is a no-op. */
    CHECK(ppm_store_ingest_tarball(s, tar_path, &expected) == PPM_OK);

    /* Wrong expected hash is refused. */
    ppm_sha512_t wrong = expected;
    wrong.bytes[0] ^= 0xFF;
    CHECK(ppm_store_ingest_tarball(s, tar_path, &wrong) == PPM_ERR_HASH_MISMATCH);

    int bad = -1;
    CHECK(ppm_store_verify(s, &bad) == PPM_OK);
    CHECK(bad == 0);

    ppm_store_close(s);
    ppm_path_rmrf(base);
    free(store_root); free(tar_path); free(obj_path); free(file_in_store);
    printf("ok\n");
    return 0;
}
