/* Generated by cbindgen — do not edit manually. */

#ifndef FFF_C_H
#define FFF_C_H

/* Generated with cbindgen:0.29.2 */

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

/**
 * Current used version of [`FffCreateOptions`].
 */
#define FFF_CREATE_OPTIONS_VERSION 2

/**
 * Current version of [`FffWatchOptions`].
 */
#define FFF_WATCH_OPTIONS_VERSION 1

/**
 * Result envelope returned by all `fff_*` functions.
 *
 * Heap-allocated. The caller must free it with `fff_free_result`. Calling `fff_free_result`
 * **does not** deallocate the underlying `handle` pointer. It needs to be cleaned separately.
 * see (`fff_destroy`, `fff_free_search_result`, `fff_free_grep_result`, `fff_free_string`, etc.).
 *
 * Depending on the function, the payload is delivered through different fields:
 *
 * | Function                   | Payload field | Type                          |
 * |----------------------------|---------------|-------------------------------|
 * | `fff_create_instance`      | `handle`      | opaque instance pointer       |
 * | `fff_search`               | `handle`      | `*mut FffSearchResult`        |
 * | `fff_live_grep`            | `handle`      | `*mut FffGrepResult`          |
 * | `fff_multi_grep`           | `handle`      | `*mut FffGrepResult`          |
 * | `fff_get_scan_progress`    | `handle`      | `*mut FffScanProgress`        |
 * | `fff_health_check`         | `handle`      | `*mut c_char` (JSON string)   |
 * | `fff_get_historical_query` | `handle`      | `*mut c_char` (string or null)|
 * | `fff_wait_for_scan`        | `int_value`   | 1 = completed, 0 = timed out  |
 * | `fff_track_query`          | `int_value`   | 1 = success, 0 = failure      |
 * | `fff_refresh_git_status`   | `int_value`   | number of files updated       |
 * | `fff_scan_files`           | (none)        | success flag only             |
 * | `fff_restart_index`        | (none)        | success flag only             |
 *
 * On failure, `success` is false and `error` contains the message.
 */
typedef struct FffResult {
  /**
   * Whether the operation succeeded.
   */
  bool success;
  /**
   * Error message on failure. Null on success.
   */
  char *error;
  /**
   * Opaque pointer payload. May be null.
   */
  void *handle;
  /**
   * Integer payload for simple return values (bool as 0/1, counts, etc.).
   */
  int64_t int_value;
} FffResult;

/**
 * Options for `fff_create_instance_with`.
 *
 * Versioned struct: the layout is stable across releases, new fields are
 * only appended.
 */
typedef struct FffCreateOptions {
  /**
   * Set to [`FFF_CREATE_OPTIONS_VERSION`] when allocating; tells the
   * library which trailing fields are populated.
   */
  uint32_t version;
  /**
   * Directory to index (required, non-NULL).
   */
  const char *base_path;
  /**
   * Frecency LMDB database path. NULL/empty to skip frecency tracking.
   */
  const char *frecency_db_path;
  /**
   * Query history LMDB database path. NULL/empty to skip query tracking.
   */
  const char *history_db_path;
  /**
   * Pre-populate mmap caches for top-frecency files after the initial scan.
   */
  bool enable_mmap_cache;
  /**
   * Build content index after the initial scan for faster grep.
   */
  bool enable_content_indexing;
  /**
   * Start a background file-system watcher for live updates.
   */
  bool watch;
  /**
   * Enable AI-agent optimizations.
   */
  bool ai_mode;
  /**
   * Tracing log file path. NULL/empty to skip log init.
   */
  const char *log_file_path;
  /**
   * Log level: `"trace" | "debug" | "info" | "warn" | "error"`.
   * NULL/empty defaults to `"info"`. Ignored when `log_file_path` is unset.
   */
  const char *log_level;
  /**
   * Content cache file-count cap. 0 = auto.
   */
  uint64_t cache_budget_max_files;
  /**
   * Content cache byte cap. 0 = auto.
   */
  uint64_t cache_budget_max_bytes;
  /**
   * Per-file byte cap inside the content cache. 0 = auto.
   */
  uint64_t cache_budget_max_file_size;
  /**
   * Allow indexing the filesystem root (`/`). Off by default: root is rarely
   * intended and floods the watcher with churn.
   */
  bool enable_fs_root_scanning;
  /**
   * Allow indexing the user's home directory. Same trade-off as `enable_fs_root_scanning`.
   */
  bool enable_home_dir_scanning;
  /**
   * Follow symlinks during scan and watcher walks. Off by default: without
   * external loop protection cyclic symlinks can wedge the watcher.
   */
  bool follow_symlinks;
} FffCreateOptions;

/**
 * A file item returned by `fff_search`. Strings are owned by the parent
 * `FffSearchResult`; free everything with `fff_free_search_result`.
 */
typedef struct FffFileItem {
  char *relative_path;
  char *file_name;
  char *git_status;
  uint64_t size;
  uint64_t modified;
  int64_t access_frecency_score;
  int64_t modification_frecency_score;
  int64_t total_frecency_score;
  bool is_binary;
} FffFileItem;

/**
 * Score breakdown for a search result.
 */
typedef struct FffScore {
  int32_t total;
  int32_t base_score;
  int32_t filename_bonus;
  int32_t special_filename_bonus;
  int32_t frecency_boost;
  int32_t distance_penalty;
  int32_t current_file_penalty;
  int32_t combo_match_boost;
  int32_t path_alignment_bonus;
  bool exact_match;
  char *match_type;
} FffScore;

/**
 * Location parsed from a query string (e.g. `"file.ts:42:10"`). `tag`:
 * 0 = none, 1 = line, 2 = position (`line` + `col`),
 * 3 = range (`line`/`col` = start, `end_line`/`end_col` = end).
 */
typedef struct FffLocation {
  uint8_t tag;
  int32_t line;
  int32_t col;
  int32_t end_line;
  int32_t end_col;
} FffLocation;

/**
 * Search result returned by `fff_search`; free with `fff_free_search_result`.
 */
typedef struct FffSearchResult {
  /**
   * Heap array of `FffFileItem` (length = `count`).
   */
  struct FffFileItem *items;
  /**
   * Heap array of `FffScore` (length = `count`).
   */
  struct FffScore *scores;
  /**
   * Number of items/scores in the arrays.
   */
  uint32_t count;
  /**
   * Total number of files that matched the query.
   */
  uint32_t total_matched;
  /**
   * Total number of indexed files.
   */
  uint32_t total_files;
  /**
   * Location parsed from the query string.
   */
  struct FffLocation location;
} FffSearchResult;

/**
 * A byte range within a matched line, used for highlighting.
 */
typedef struct FffMatchRange {
  uint32_t start;
  uint32_t end;
} FffMatchRange;

/**
 * A single grep match with file and line information. Strings and arrays are
 * owned by the parent `FffGrepResult`; free everything with `fff_free_grep_result`.
 */
typedef struct FffGrepMatch {
  char *relative_path;
  char *file_name;
  char *git_status;
  char *line_content;
  struct FffMatchRange *match_ranges;
  char **context_before;
  char **context_after;
  uint64_t size;
  uint64_t modified;
  int64_t total_frecency_score;
  int64_t access_frecency_score;
  int64_t modification_frecency_score;
  uint64_t line_number;
  uint64_t byte_offset;
  uint32_t col;
  uint32_t match_ranges_count;
  uint32_t context_before_count;
  uint32_t context_after_count;
  uint16_t fuzzy_score;
  bool has_fuzzy_score;
  bool is_binary;
  bool is_definition;
} FffGrepMatch;

/**
 * Grep result returned by `fff_live_grep` and `fff_multi_grep`;
 * free with `fff_free_grep_result`.
 */
typedef struct FffGrepResult {
  /**
   * Heap array of `FffGrepMatch` (length = `count`).
   */
  struct FffGrepMatch *items;
  /**
   * Number of matches in the `items` array.
   */
  uint32_t count;
  /**
   * Total number of matches (always equal to `count`).
   */
  uint32_t total_matched;
  /**
   * Number of files actually opened and searched in this call.
   */
  uint32_t total_files_searched;
  /**
   * Total number of indexed files (before any filtering).
   */
  uint32_t total_files;
  /**
   * Number of files eligible for search after filtering.
   */
  uint32_t filtered_file_count;
  /**
   * File offset for the next page. 0 if all files have been searched.
   */
  uint32_t next_file_offset;
  /**
   * Regex compilation error when falling back to literal matching. Null if none.
   */
  char *regex_fallback_error;
} FffGrepResult;

/**
 * Scan progress returned by `fff_get_scan_progress`.
 * The caller must free this with `fff_free_scan_progress`.
 */
typedef struct FffScanProgress {
  uint64_t scanned_files_count;
  bool is_scanning;
  bool is_watcher_ready;
  bool is_warmup_complete;
} FffScanProgress;

/**
 * A directory item returned by `fff_search_directories`. Strings are owned by
 * the parent `FffDirSearchResult`; free everything with `fff_free_dir_search_result`.
 */
typedef struct FffDirItem {
  char *relative_path;
  char *dir_name;
  int32_t max_access_frecency;
} FffDirItem;

/**
 * Directory search result returned by `fff_search_directories`;
 * free with `fff_free_dir_search_result`.
 */
typedef struct FffDirSearchResult {
  /**
   * Heap array of `FffDirItem` (length = `count`).
   */
  struct FffDirItem *items;
  /**
   * Heap array of `FffScore` (length = `count`).
   */
  struct FffScore *scores;
  /**
   * Number of items/scores in the arrays.
   */
  uint32_t count;
  /**
   * Total number of directories that matched the query.
   */
  uint32_t total_matched;
  /**
   * Total number of indexed directories.
   */
  uint32_t total_dirs;
} FffDirSearchResult;

/**
 * A single item in a mixed (files + directories) search result.
 * `item_type`: 0 = file, 1 = directory. Strings are owned by the parent
 * `FffMixedSearchResult`.
 */
typedef struct FffMixedItem {
  /**
   * 0 = file, 1 = directory.
   */
  uint8_t item_type;
  char *relative_path;
  /**
   * Filename for files, last directory segment for directories.
   */
  char *display_name;
  char *git_status;
  uint64_t size;
  uint64_t modified;
  /**
   * Access frecency for files; max among immediate children for directories.
   */
  int64_t access_frecency_score;
  /**
   * Always 0 for directories
   */
  int64_t modification_frecency_score;
  /**
   * Always 0 for directories
   */
  int64_t total_frecency_score;
  /**
   * Always 0 for directories
   */
  bool is_binary;
} FffMixedItem;

/**
 * Mixed search result returned by `fff_search_mixed`
 * free with `fff_free_mixed_search_result`.
 */
typedef struct FffMixedSearchResult {
  /**
   * Heap array of `FffMixedItem` (length = `count`).
   */
  struct FffMixedItem *items;
  /**
   * Heap array of `FffScore` (length = `count`).
   */
  struct FffScore *scores;
  /**
   * Number of items/scores in the arrays.
   */
  uint32_t count;
  /**
   * Total number of items (files + dirs) that matched the query.
   */
  uint32_t total_matched;
  /**
   * Total number of indexed files.
   */
  uint32_t total_files;
  /**
   * Total number of indexed directories.
   */
  uint32_t total_dirs;
  /**
   * Location parsed from the query string.
   */
  struct FffLocation location;
} FffMixedSearchResult;

/**
 * A single watch event. `kind`: 0 = created, 1 = modified, 2 = removed,
 * 3 = rescan (events were lost; re-stat what you care about).
 */
typedef struct FffWatchEvent {
  /**
   * Absolute path (heap C string owned by the parent batch).
   */
  char *path;
  uint8_t kind;
} FffWatchEvent;

/**
 * A batch of watch events. Free with `fff_free_watch_events`.
 */
typedef struct FffWatchEventBatch {
  struct FffWatchEvent *events;
  uint32_t count;
} FffWatchEventBatch;

/**
 * Instance-wide callback invoked with `(watch_id, batch)` for every `fff_watch`
 * subscription. The callee owns and frees `batch` via `fff_free_watch_events`.
 */
typedef void (*FffWatchCallback)(uint64_t watch_id,
                                 struct FffWatchEventBatch *batch,
                                 void *user_data);

/**
 * Options for `fff_watch`. Versioned: new fields are only appended.
 */
typedef struct FffWatchOptions {
  /**
   * Set to [`FFF_WATCH_OPTIONS_VERSION`] when allocating.
   */
  uint32_t version;
  /**
   * Per-subscription excludes (parcel-watcher style): entries with wildcards
   * are base-relative globs, entries without are path prefixes. NULL when
   * `ignore_count` is 0.
   */
  const char *const *ignore;
  uint32_t ignore_count;
} FffWatchOptions;

/**
 * Create a new file finder instance (legacy 8-arg positional signature).
 *
 * @deprecated Use [`fff_create_instance_with`] (or [`fff_create_instance_with_value`]
 * for FFI bindings). The `use_unsafe_no_lock` parameter is ignored.
 *
 * ## Safety
 * See `fff_create_instance_with`.
 */
__attribute__((deprecated("Use fff_create_instance_with (by pointer) or fff_create_instance_with_value (by value) with FffCreateOptions instead. The struct evolves without ABI breaks.")))
struct FffResult *fff_create_instance(const char *base_path,
                                      const char *frecency_db_path,
                                      const char *history_db_path,
                                      bool _use_unsafe_no_lock,
                                      bool enable_mmap_cache,
                                      bool enable_content_indexing,
                                      bool watch,
                                      bool ai_mode);

/**
 * Create a new file finder instance (legacy 13-arg positional signature).
 *
 * @deprecated Use [`fff_create_instance_with`] (or [`fff_create_instance_with_value`]
 * for FFI bindings). The `use_unsafe_no_lock` parameter is ignored.
 *
 * ## Safety
 * See `fff_create_instance_with`.
 */
__attribute__((deprecated("Use fff_create_instance_with (by pointer) or fff_create_instance_with_value (by value) with FffCreateOptions instead. The struct evolves without ABI breaks.")))
struct FffResult *fff_create_instance2(const char *base_path,
                                       const char *frecency_db_path,
                                       const char *history_db_path,
                                       bool _use_unsafe_no_lock,
                                       bool enable_mmap_cache,
                                       bool enable_content_indexing,
                                       bool watch,
                                       bool ai_mode,
                                       const char *log_file_path,
                                       const char *log_level,
                                       uint64_t cache_budget_max_files,
                                       uint64_t cache_budget_max_bytes,
                                       uint64_t cache_budget_max_file_size);

/**
 * Create a new file finder instance from a versioned [`FffCreateOptions`] struct.
 *
 * Populate the struct, set `version` to [`FFF_CREATE_OPTIONS_VERSION`], pass by
 * pointer. New fields are only appended; older `version` values keep working.
 * FFI bindings needing struct-by-value should use [`fff_create_instance_with_value`].
 *
 * `opts.base_path` is required (non-NULL, non-empty). Zero `cache_budget_*`
 * values are auto-computed from repo size after the initial scan.
 *
 * ## Safety
 * * `opts` must be a valid pointer to an `FffCreateOptions` whose `version`
 *   is in the range `1..=FFF_CREATE_OPTIONS_VERSION`.
 * * All string pointers inside `opts` must be valid null-terminated UTF-8
 *   or NULL.
 */
struct FffResult *fff_create_instance_with(const struct FffCreateOptions *opts);

/**
 * [`fff_create_instance_with`] adapter taking [`FffCreateOptions`] **by value**,
 * for FFI libraries that pass native structs by value (e.g. Node's `ffi-rs`).
 *
 * ## Safety
 * All `*const c_char` fields inside `opts` must be valid null-terminated
 * UTF-8 or NULL. The struct itself is consumed by value.
 */
struct FffResult *fff_create_instance_with_value(struct FffCreateOptions opts);

/**
 * Destroy a file finder instance and free all its resources.
 *
 * ## Safety
 * `fff_handle` must be a valid pointer returned by `fff_create_instance`, or null (no-op).
 */
void fff_destroy(void *fff_handle);

/**
 * Perform fuzzy search on indexed files.
 *
 * `current_file` deprioritizes the currently open file (NULL/empty to skip).
 * Zero picks the default: `max_threads` auto, `page_size` 100,
 * `combo_boost_multiplier` 100, `min_combo_count` 3.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `query` and `current_file` must be valid null-terminated UTF-8 strings or NULL.
 */
struct FffResult *fff_search(void *fff_handle,
                             const char *query,
                             const char *current_file,
                             uint32_t max_threads,
                             uint32_t page_index,
                             uint32_t page_size,
                             int32_t combo_boost_multiplier,
                             uint32_t min_combo_count);

/**
 * Glob-only search: filter indexed files by a single glob pattern (passed
 * through verbatim, no query parsing), rank by frecency, and paginate.
 *
 * `current_file` deprioritizes the currently open file (NULL/empty to skip).
 * Zero picks the default: `max_threads` auto, `page_size` 100.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `pattern` and `current_file` must be valid null-terminated UTF-8 strings or NULL.
 */
struct FffResult *fff_glob(void *fff_handle,
                           const char *pattern,
                           const char *current_file,
                           uint32_t max_threads,
                           uint32_t page_index,
                           uint32_t page_size);

/**
 * Perform fuzzy search on indexed directories.
 *
 * `current_file` is used for distance scoring (NULL/empty to skip).
 * Zero picks the default: `max_threads` auto, `page_size` 100.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `query` and `current_file` must be valid null-terminated UTF-8 strings or NULL.
 */
struct FffResult *fff_search_directories(void *fff_handle,
                                         const char *query,
                                         const char *current_file,
                                         uint32_t max_threads,
                                         uint32_t page_index,
                                         uint32_t page_size);

/**
 * Perform a mixed fuzzy search across both files and directories.
 *
 * Returns one flat list interleaved by descending total score; each item's
 * `item_type` is 0 = file, 1 = directory. Parameters as in [`fff_search`].
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `query` and `current_file` must be valid null-terminated UTF-8 strings or NULL.
 */
struct FffResult *fff_search_mixed(void *fff_handle,
                                   const char *query,
                                   const char *current_file,
                                   uint32_t max_threads,
                                   uint32_t page_index,
                                   uint32_t page_size,
                                   int32_t combo_boost_multiplier,
                                   uint32_t min_combo_count);

/**
 * Perform content search (grep) across indexed files.
 *
 * `query` supports constraint syntax like `*.rs pattern`; `mode` is
 * 0 = plain text (SIMD), 1 = regex, 2 = fuzzy. Zero picks the default:
 * `max_file_size` 10 MB, `page_limit` 50, `max_matches_per_file` and
 * `time_budget_ms` unlimited. `smart_case` is case-insensitive for
 * all-lowercase queries; `classify_definitions` tags code definitions.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `query` must be a valid null-terminated UTF-8 string.
 */
struct FffResult *fff_live_grep(void *fff_handle,
                                const char *query,
                                uint8_t mode,
                                uint64_t max_file_size,
                                uint32_t max_matches_per_file,
                                bool smart_case,
                                uint32_t file_offset,
                                uint32_t page_limit,
                                uint64_t time_budget_ms,
                                uint32_t before_context,
                                uint32_t after_context,
                                bool classify_definitions);

/**
 * Multi-pattern OR search (SIMD Aho-Corasick): lines matching ANY pattern.
 *
 * `patterns_joined` is `\n`-separated (e.g. `"foo\nbar"`); `constraints` is an
 * optional file filter like `"*.rs"` or `"/src/"` (NULL/empty to skip).
 * Remaining parameters as in [`fff_live_grep`].
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `patterns_joined` and `constraints` must be valid null-terminated UTF-8 or NULL.
 */
struct FffResult *fff_multi_grep(void *fff_handle,
                                 const char *patterns_joined,
                                 const char *constraints,
                                 uint64_t max_file_size,
                                 uint32_t max_matches_per_file,
                                 bool smart_case,
                                 uint32_t file_offset,
                                 uint32_t page_limit,
                                 uint64_t time_budget_ms,
                                 uint32_t before_context,
                                 uint32_t after_context,
                                 bool classify_definitions);

/**
 * Trigger a rescan of the file index.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_scan_files(void *fff_handle);

/**
 * Check if a scan is currently in progress.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
bool fff_is_scanning(void *fff_handle);

/**
 * Get the picker's base path as a heap C string in `handle`;
 * free it with `fff_free_string`.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_get_base_path(void *fff_handle);

/**
 * Get scan progress information.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_get_scan_progress(void *fff_handle);

/**
 * Wait for initial scan to complete.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_wait_for_scan(void *fff_handle, uint64_t timeout_ms);

/**
 * Wait for the background file watcher to be ready.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_wait_for_watcher(void *fff_handle, uint64_t timeout_ms);

/**
 * Restart indexing in a new directory.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `new_path` must be a valid null-terminated UTF-8 string.
 */
struct FffResult *fff_restart_index(void *fff_handle, const char *new_path);

/**
 * Refresh git status cache.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_refresh_git_status(void *fff_handle);

/**
 * Track query completion for smart suggestions.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `query` and `file_path` must be valid null-terminated UTF-8 strings.
 */
struct FffResult *fff_track_query(void *fff_handle, const char *query, const char *file_path);

/**
 * Get historical query by offset (0 = most recent).
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_get_historical_query(void *fff_handle, uint64_t offset);

/**
 * Get health check information.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`, or null for
 *   a limited health check (version + git only).
 * * `test_path` can be null or a valid null-terminated UTF-8 string.
 */
struct FffResult *fff_health_check(void *fff_handle, const char *test_path);

/**
 * Free a search result returned by `fff_search`: the struct, its `items`
 * and `scores` arrays, and every string within.
 *
 * ## Safety
 * `result` must be a valid pointer previously returned via `FffResult.handle`
 * from `fff_search`, or null (no-op).
 */
void fff_free_search_result(struct FffSearchResult *result);

/**
 * Pointer to the `index`-th `FffFileItem`; null if `result` is null or
 * `index >= count`. Valid until the search result is freed.
 *
 * ## Safety
 * `result` must be a valid `FffSearchResult` pointer from `fff_search`.
 */
const struct FffFileItem *fff_search_result_get_item(const struct FffSearchResult *result,
                                                     uint32_t index);

/**
 * Pointer to the `index`-th `FffScore`; null if `result` is null or
 * `index >= count`. Valid until the search result is freed.
 *
 * ## Safety
 * `result` must be a valid `FffSearchResult` pointer from `fff_search`.
 */
const struct FffScore *fff_search_result_get_score(const struct FffSearchResult *result,
                                                   uint32_t index);

/**
 * Free a grep result returned by `fff_live_grep` or `fff_multi_grep`:
 * the struct, its `items` array, and all strings/ranges/context within.
 *
 * ## Safety
 * `result` must be a valid pointer previously returned via `FffResult.handle`
 * from `fff_live_grep` or `fff_multi_grep`, or null (no-op).
 */
void fff_free_grep_result(struct FffGrepResult *result);

/**
 * Pointer to the `index`-th `FffGrepMatch`; null if `result` is null or
 * `index >= count`. Valid until the grep result is freed.
 *
 * ## Safety
 * `result` must be a valid `FffGrepResult` pointer from `fff_live_grep` or `fff_multi_grep`.
 */
const struct FffGrepMatch *fff_grep_result_get_match(const struct FffGrepResult *result,
                                                     uint32_t index);

/**
 * Free a scan progress result returned by `fff_get_scan_progress`.
 *
 * ## Safety
 * `result` must be a valid pointer previously returned via `FffResult.handle`
 * from `fff_get_scan_progress`, or null (no-op).
 */
void fff_free_scan_progress(struct FffScanProgress *result);

/**
 * Offset a pointer by `byte_offset` bytes (FFI array iteration helper).
 * Returns null if `base` is null.
 *
 * ## Safety
 * The resulting pointer must be within the bounds of the original allocation.
 */
const void *fff_ptr_offset(const void *base, uintptr_t byte_offset);

/**
 * Free a result envelope returned by any `fff_*` function.
 * **IMPORTANT:** the `handle` payload is NOT freed release it separately
 * using handle specific cleaning methods (`fff_destroy`, `fff_free_search_result`, etc.).
 *
 * ## Safety
 * `result_ptr` must be a valid pointer returned by a `fff_*` function.
 */
void fff_free_result(struct FffResult *result_ptr);

/**
 * Free a string returned by `fff_*` functions.
 *
 * ## Safety
 * `s` must be a valid C string allocated by this library.
 */
void fff_free_string(char *s);

/**
 * Free a directory search result returned by `fff_search_directories`.
 *
 * ## Safety
 * `result` must be a valid pointer previously returned via `FffResult.handle`
 * from `fff_search_directories`, or null (no-op).
 */
void fff_free_dir_search_result(struct FffDirSearchResult *result);

/**
 * Get a pointer to the `index`-th `FffDirItem` in a directory search result.
 *
 * ## Safety
 * `result` must be a valid `FffDirSearchResult` pointer from `fff_search_directories`.
 */
const struct FffDirItem *fff_dir_search_result_get_item(const struct FffDirSearchResult *result,
                                                        uint32_t index);

/**
 * Get a pointer to the `index`-th `FffScore` in a directory search result.
 *
 * ## Safety
 * `result` must be a valid `FffDirSearchResult` pointer from `fff_search_directories`.
 */
const struct FffScore *fff_dir_search_result_get_score(const struct FffDirSearchResult *result,
                                                       uint32_t index);

/**
 * Free a mixed search result returned by `fff_search_mixed`.
 *
 * ## Safety
 * `result` must be a valid pointer previously returned via `FffResult.handle`
 * from `fff_search_mixed`, or null (no-op).
 */
void fff_free_mixed_search_result(struct FffMixedSearchResult *result);

/**
 * Get a pointer to the `index`-th `FffMixedItem` in a mixed search result.
 *
 * ## Safety
 * `result` must be a valid `FffMixedSearchResult` pointer from `fff_search_mixed`.
 */
const struct FffMixedItem *fff_mixed_search_result_get_item(const struct FffMixedSearchResult *result,
                                                            uint32_t index);

/**
 * Get a pointer to the `index`-th `FffScore` in a mixed search result.
 *
 * ## Safety
 * `result` must be a valid `FffMixedSearchResult` pointer from `fff_search_mixed`.
 */
const struct FffScore *fff_mixed_search_result_get_score(const struct FffMixedSearchResult *result,
                                                         uint32_t index);

/**
 * Returns whether the operation completed successfully. Returns `false` if `result` is null.
 *
 * ## Safety
 * `result` must be a valid `FffResult` pointer or null.
 */
bool fff_result_get_success(const struct FffResult *result);

/**
 * Returns the operation error message, or null when there is no error or `result` is null.
 *
 * Do not free the returned pointer. It remains valid until `fff_free_result` is called.
 *
 * ## Safety
 * `result` must be a valid `FffResult` pointer or null.
 */
const char *fff_result_get_error(const struct FffResult *result);

/**
 * Returns the result payload handle, or null if `result` is null.
 *
 * ## Safety
 * `result` must be a valid `FffResult` pointer or null.
 */
void *fff_result_get_handle(const struct FffResult *result);

/**
 * Returns the result integer payload. Returns `0` if `result` is null.
 *
 * ## Safety
 * `result` must be a valid `FffResult` pointer or null.
 */
int64_t fff_result_get_int_value(const struct FffResult *result);

/**
 * Relative path of a file item (e.g. `"src/main.rs"`); null if `item` is null. Do not free.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
const char *fff_file_item_get_relative_path(const struct FffFileItem *item);

/**
 * File-name component of a file item (e.g. `"main.rs"`); null if `item` is null. Do not free.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
const char *fff_file_item_get_file_name(const struct FffFileItem *item);

/**
 * Git status string of a file item (e.g. `"M "`, `"??"`); null if git is unavailable,
 * the file is untracked, or `item` is null. Do not free.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
const char *fff_file_item_get_git_status(const struct FffFileItem *item);

/**
 * File size in bytes; `0` if `item` is null.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
uint64_t fff_file_item_get_size(const struct FffFileItem *item);

/**
 * Last-modified time as seconds since the UNIX epoch; `0` if `item` is null.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
uint64_t fff_file_item_get_modified(const struct FffFileItem *item);

/**
 * Combined frecency score; `0` if `item` is null.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
int64_t fff_file_item_get_total_frecency_score(const struct FffFileItem *item);

/**
 * Access-based frecency score; `0` if `item` is null.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
int64_t fff_file_item_get_access_frecency_score(const struct FffFileItem *item);

/**
 * Modification-based frecency score; `0` if `item` is null.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
int64_t fff_file_item_get_modification_frecency_score(const struct FffFileItem *item);

/**
 * `true` if the file was detected as binary; `false` if `item` is null.
 *
 * ## Safety
 * `item` must be a valid `FffFileItem` pointer or null.
 */
bool fff_file_item_get_is_binary(const struct FffFileItem *item);

/**
 * Relative path of the file containing this grep match; null if `m` is null. Do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const char *fff_grep_match_get_relative_path(const struct FffGrepMatch *m);

/**
 * File-name component of the file containing this grep match; null if `m` is null. Do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const char *fff_grep_match_get_file_name(const struct FffGrepMatch *m);

/**
 * Git status string of the matched file (e.g. `"M "`, `"??"`); null if git is unavailable,
 * the file is untracked, or `m` is null. Do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const char *fff_grep_match_get_git_status(const struct FffGrepMatch *m);

/**
 * Full text content of the matched line; null if `m` is null. Do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const char *fff_grep_match_get_line_content(const struct FffGrepMatch *m);

/**
 * 1-based line number of the match within its file; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint64_t fff_grep_match_get_line_number(const struct FffGrepMatch *m);

/**
 * 0-based column of the match start within its line; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint32_t fff_grep_match_get_col(const struct FffGrepMatch *m);

/**
 * Byte offset of the match start from the beginning of the file; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint64_t fff_grep_match_get_byte_offset(const struct FffGrepMatch *m);

/**
 * File size in bytes of the matched file; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint64_t fff_grep_match_get_size(const struct FffGrepMatch *m);

/**
 * Combined frecency score of the matched file; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
int64_t fff_grep_match_get_total_frecency_score(const struct FffGrepMatch *m);

/**
 * Access-based frecency score of the matched file; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
int64_t fff_grep_match_get_access_frecency_score(const struct FffGrepMatch *m);

/**
 * Modification-based frecency score of the matched file; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
int64_t fff_grep_match_get_modification_frecency_score(const struct FffGrepMatch *m);

/**
 * Last-modified time of the matched file as seconds since the UNIX epoch; `0` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint64_t fff_grep_match_get_modified(const struct FffGrepMatch *m);

/**
 * Number of highlight ranges in this match; `0` if `m` is null.
 * Use with [`fff_grep_match_get_match_range`] to iterate the highlight spans.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint32_t fff_grep_match_get_match_ranges_count(const struct FffGrepMatch *m);

/**
 * Pointer to the `index`-th [`FffMatchRange`] highlight span; null if `m` is null,
 * `index >= match_ranges_count`, or the ranges array is null. Valid until the owning `FffGrepResult` is freed; do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const struct FffMatchRange *fff_grep_match_get_match_range(const struct FffGrepMatch *m,
                                                           uint32_t index);

/**
 * Number of context lines captured before the match; `0` if `m` is null.
 * Use with [`fff_grep_match_get_context_before`] to read each line.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint32_t fff_grep_match_get_context_before_count(const struct FffGrepMatch *m);

/**
 * The `index`-th context line before the match; null if `m` is null,
 * `index >= context_before_count`, or the context array is null. Do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const char *fff_grep_match_get_context_before(const struct FffGrepMatch *m, uint32_t index);

/**
 * Number of context lines captured after the match; `0` if `m` is null.
 * Use with [`fff_grep_match_get_context_after`] to read each line.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint32_t fff_grep_match_get_context_after_count(const struct FffGrepMatch *m);

/**
 * The `index`-th context line after the match; null if `m` is null,
 * `index >= context_after_count`, or the context array is null. Do not free.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
const char *fff_grep_match_get_context_after(const struct FffGrepMatch *m, uint32_t index);

/**
 * Fuzzy match score; `0` if `m` is null or no fuzzy score is present.
 * Always check [`fff_grep_match_get_has_fuzzy_score`] first; `0` is ambiguous without that flag.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
uint16_t fff_grep_match_get_fuzzy_score(const struct FffGrepMatch *m);

/**
 * `true` if this match carries a valid fuzzy score; `false` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
bool fff_grep_match_get_has_fuzzy_score(const struct FffGrepMatch *m);

/**
 * `true` if the match was identified as a symbol definition; `false` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
bool fff_grep_match_get_is_definition(const struct FffGrepMatch *m);

/**
 * `true` if the matched file was detected as binary; `false` if `m` is null.
 *
 * ## Safety
 * `m` must be a valid `FffGrepMatch` pointer or null.
 */
bool fff_grep_match_get_is_binary(const struct FffGrepMatch *m);

/**
 * Number of items in the result; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffSearchResult` pointer or null.
 */
uint32_t fff_search_result_get_count(const struct FffSearchResult *r);

/**
 * Total number of files that matched before truncation to the page size; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffSearchResult` pointer or null.
 */
uint32_t fff_search_result_get_total_matched(const struct FffSearchResult *r);

/**
 * Total number of indexed files considered during search; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffSearchResult` pointer or null.
 */
uint32_t fff_search_result_get_total_files(const struct FffSearchResult *r);

/**
 * Number of matches in the result; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
uint32_t fff_grep_result_get_count(const struct FffGrepResult *r);

/**
 * Total number of matches found across all pages; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
uint32_t fff_grep_result_get_total_matched(const struct FffGrepResult *r);

/**
 * Number of files actually opened and searched in this call; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
uint32_t fff_grep_result_get_total_files_searched(const struct FffGrepResult *r);

/**
 * Total number of indexed files before any filtering; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
uint32_t fff_grep_result_get_total_files(const struct FffGrepResult *r);

/**
 * Number of files eligible for search after path/type filtering; `0` if `r` is null.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
uint32_t fff_grep_result_get_filtered_file_count(const struct FffGrepResult *r);

/**
 * File offset for the next page; `0` if all files have been searched or `r` is null.
 * Pass as `file_offset` to a subsequent `fff_live_grep`/`fff_multi_grep` call to continue pagination.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
uint32_t fff_grep_result_get_next_file_offset(const struct FffGrepResult *r);

/**
 * Regex compilation error string if the engine fell back to literal matching;
 * null if there was no error or `r` is null. Do not free.
 *
 * ## Safety
 * `r` must be a valid `FffGrepResult` pointer or null.
 */
const char *fff_grep_result_get_regex_fallback_error(const struct FffGrepResult *r);

/**
 * Register the instance-wide watch callback used by all `fff_watch`
 * subscriptions; call before the first `fff_watch`, calling again replaces it.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `callback` must remain callable until fff_unwatch called
 *   `fff_destroy(fff_handle)` returns.
 */
struct FffResult *fff_set_watch_callback(void *fff_handle,
                                         FffWatchCallback callback,
                                         void *user_data);

/**
 * Subscribe to filesystem changes, delivered through the instance callback
 * registered by `fff_set_watch_callback`.
 *
 * Returns the watch id, pass it to `fff_unwatch` to stop.
 *
 * `pattern` if non `NULL` can be wildcard pattern, absolute, or relative path
 * that will be used to filter the events triggering exact subscription.
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `pattern` must be NULL or valid null-terminated UTF-8.
 * * `opts` must be NULL or a valid `FffWatchOptions` pointer.
 */
struct FffResult *fff_watch(void *fff_handle,
                            const char *pattern,
                            const struct FffWatchOptions *opts);

/**
 * [`fff_watch`] adapter with flattened options, for FFI libraries that cannot
 * marshal pointer arrays inside structs (e.g. Node's `ffi-rs`).
 *
 * ## Safety
 * * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 * * `pattern` must be NULL (watch everything) or valid null-terminated UTF-8.
 * * `ignore` must be NULL or point to `ignore_count` valid C strings.
 */
struct FffResult *fff_watch_args(void *fff_handle,
                                 const char *pattern,
                                 const char *const *ignore,
                                 uint32_t ignore_count);

/**
 * Remove a watch subscription. `int_value` = 1 if the id existed, 0 otherwise.
 *
 * ## Safety
 * `fff_handle` must be a valid instance pointer from `fff_create_instance`.
 */
struct FffResult *fff_unwatch(void *fff_handle, uint64_t watch_id);

/**
 * Number of events in a batch; 0 if `batch` is null.
 *
 * ## Safety
 * `batch` must be a valid `FffWatchEventBatch` pointer or null.
 */
uint32_t fff_watch_events_count(const struct FffWatchEventBatch *batch);

/**
 * Absolute path of event `index`, will be null when out of bounds
 *
 * ## Safety
 * `batch` must be a valid `FffWatchEventBatch` pointer or null.
 */
const char *fff_watch_events_get_path(const struct FffWatchEventBatch *batch, uint32_t index);

/**
 * Kind of event `index` (0 = created, 1 = modified, 2 = removed, 3 = rescan)
 * 3 (rescan aka "re-stat something" kind) returned when OS based buffer
 * has been overflown and some events might be loss. Paths will contain a list of
 * directories that needs to be rescanned to ensure consistency.
 *
 * ## Safety
 * `batch` must be a valid `FffWatchEventBatch` pointer or null.
 */
uint8_t fff_watch_events_get_kind(const struct FffWatchEventBatch *batch, uint32_t index);

/**
 * Free a watch event batch delivered to the instance callback.
 *
 * ## Safety
 * `batch` must be a pointer produced by this library, or null (no-op).
 */
void fff_free_watch_events(struct FffWatchEventBatch *batch);

#endif  /* FFF_C_H */
