// PRE Native Inference Engine — llama.cpp C API integration
// Provides direct GPU inference without Ollama HTTP overhead.
// macOS Apple Silicon only (Metal backend).
//
// Usage:
//   inference_engine_t *eng = inference_init(model_path, n_ctx);
//   if (!eng) { /* fallback to Ollama */ }
//   inference_generate(eng, messages, n_messages, on_token, userdata);
//   inference_free(eng);

#ifndef PRE_INFERENCE_H
#define PRE_INFERENCE_H

#include <stdint.h>
#include <stdbool.h>

#ifdef __cplusplus
extern "C" {
#endif

// Forward declarations — avoids pulling llama.h into pre.m
typedef struct inference_engine inference_engine_t;

// Chat message for the generate API
typedef struct {
    const char *role;    // "system", "user", "assistant", "tool"
    const char *content;
} inference_message_t;

// Token callback — called for each decoded token.
// Return false to abort generation.
typedef bool (*inference_token_cb)(const char *text, int n_bytes, void *userdata);

// Stats from a generation pass
typedef struct {
    int prompt_tokens;
    int generated_tokens;
    double prompt_eval_ms;
    double generate_ms;
    double tokens_per_sec;     // decode tok/s
    double prompt_tok_per_sec; // prefill tok/s
} inference_stats_t;

// Initialize the inference engine. Loads model from GGUF file.
// Returns NULL on failure (caller should fall back to Ollama).
// n_ctx: context window size (e.g., 131072). 0 = use model default.
inference_engine_t *inference_init(const char *model_path, int n_ctx);

// Generate a response from a conversation.
// messages: array of role/content pairs (system, user, assistant, tool turns)
// n_messages: number of messages
// max_tokens: max tokens to generate (0 = model default)
// on_token: callback for each decoded token (NULL = collect internally)
// userdata: passed to callback
// stats_out: if non-NULL, filled with timing stats
// Returns the full generated text (caller must free), or NULL on error.
char *inference_generate(inference_engine_t *eng,
                         const inference_message_t *messages, int n_messages,
                         int max_tokens,
                         inference_token_cb on_token, void *userdata,
                         inference_stats_t *stats_out);

// Save KV cache state to disk (for system prompt persistence).
bool inference_save_kv(inference_engine_t *eng, const char *path);

// Load KV cache state from disk.
bool inference_load_kv(inference_engine_t *eng, const char *path);

// Get the number of tokens currently in the KV cache.
int inference_kv_used(inference_engine_t *eng);

// Clear the KV cache.
void inference_kv_clear(inference_engine_t *eng);

// Free the engine and all resources.
void inference_free(inference_engine_t *eng);

// Resolve Ollama model tag to GGUF file path.
// Returns allocated string (caller must free) or NULL on failure.
// e.g., "pre-gemma4" -> "/Users/.../.ollama/models/blobs/sha256-..."
char *inference_resolve_ollama_model(const char *tag);

#ifdef __cplusplus
}
#endif

#endif // PRE_INFERENCE_H
