// SPDX-License-Identifier: GPL-2.0-only
/*
 *  ppm/include/ppm/manifest.h
 *
 *  Copyright (C) 2026 Project Tick
 */

#ifndef PPM_MANIFEST_H
#define PPM_MANIFEST_H

#include <stddef.h>
#include <stdint.h>

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

#ifdef __cplusplus
extern "C" {
#endif

/*
 * Manifest — the in-memory representation of a ppm.toml file, whether it
 * belongs to a local project or to a published version in the registry.
 *
 * Manifests are treated as immutable after parsing. Mutators are not part
 * of the public API.
 */

typedef struct ppm_version {
    uint32_t major;
    uint32_t minor;
    uint32_t patch;
    char    *pre;     /* nullable, e.g. "rc.1"; borrowed-from-arena */
    char    *build;   /* nullable, e.g. "20260101"                  */
} ppm_version_t;

/* Parse a SemVer 2.0.0 version string into `out`. */
ppm_error_t ppm_version_parse(const char *s, ppm_version_t *out);

/* Returns negative, zero, or positive — SemVer precedence rules. */
int ppm_version_cmp(const ppm_version_t *a, const ppm_version_t *b);

/*
 * Free the heap allocations owned by `v` (pre, build) and zero the struct.
 * The struct itself is caller-managed (often a local). Safe on NULL and
 * on a zero-initialised version.
 */
void ppm_version_dispose(ppm_version_t *v);

/*
 * Version requirement. Stored in its original textual form because the
 * resolver lazily parses each constraint. Examples: "^1.2", ">=1.0, <2.0".
 */
typedef struct ppm_req {
    char *name;
    char *spec;
} ppm_req_t;

typedef struct ppm_manifest_source {
    char         *url;     /* HTTPS URL to the tarball (tar.zst)        */
    ppm_sha512_t  hash;    /* SHA-512 of the tarball                    */
    char         *sig_url; /* nullable; defaults to url + ".sig"        */
} ppm_manifest_source_t;

/*
 * Build derivation. When present, ppm will compile from source whenever
 * the build output is not already in the content-addressed store.
 *
 * The build is executed in an isolated temp directory with two env vars:
 *   $src — the extracted source tree (read-only by convention)
 *   $out — the directory where the package must place its artefacts
 *
 * `script` runs under `/bin/sh -e`. It MUST be deterministic given the
 * same inputs (source hash, deps, system, script) so the resulting
 * out_path hash is stable across machines.
 */
typedef struct ppm_manifest_build {
    int    has_build;        /* 0 if no [build] section in the manifest */
    char  *system;           /* e.g. "x86_64-linux"; nullable -> any    */
    char  *script;           /* shell snippet, NUL-terminated           */
} ppm_manifest_build_t;

typedef struct ppm_manifest {
    char                  *name;
    ppm_version_t          version;
    char                  *summary;     /* nullable */
    char                  *license;     /* SPDX expression, nullable */
    char                 **authors;     /* NULL-terminated, nullable */
    char                  *homepage;    /* nullable */

    ppm_manifest_source_t  source;
    ppm_manifest_build_t   build;       /* has_build == 0 => binary pkg */

    ppm_req_t             *deps;        /* runtime dependencies     */
    size_t                 deps_len;

    ppm_req_t             *build_deps;  /* build-time dependencies  */
    size_t                 build_deps_len;
} ppm_manifest_t;

/* Parse a manifest from a TOML buffer or from a file on disk. */
ppm_error_t ppm_manifest_parse(const char *buf, size_t len, ppm_manifest_t **out);
ppm_error_t ppm_manifest_load (const char *path, ppm_manifest_t **out);

typedef enum ppm_manifest_mode {
    /* Local project manifest: source.url/hash may be omitted. */
    PPM_MANIFEST_LOCAL = 0,
    /* Manifest as published to the registry: source.url and source.hash
     * are mandatory and must be well-formed. */
    PPM_MANIFEST_PUBLISHED = 1,
} ppm_manifest_mode_t;

ppm_error_t ppm_manifest_validate(const ppm_manifest_t *m,
                                  ppm_manifest_mode_t mode);

/* Frees the manifest and every owned string. Safe on NULL. */
void ppm_manifest_free(ppm_manifest_t *m);

#ifdef __cplusplus
}
#endif

#endif /* PPM_MANIFEST_H */
