// viewer-tensor.h: tensor data analysis
//
// Layout computation (1D/2D/3D), tile extraction, slice statistics
// with reservoir sampling, and histogram generation.
// All functions operate on a mapped_file and a tensor_entry descriptor.

#pragma once

#include <ggml.h>

#include <cstddef>
#include <cstdint>
#include <string>
#include <vector>

struct mapped_file;

// 2D layout of a tensor for visualization
struct tensor_layout {
  size_t width = 1;
  size_t height = 1;
  size_t depth = 1;
};

// tensor descriptor: everything needed to read and visualize one tensor.
// populated at model load time from ggml_tensor* and gguf_context*.
struct tensor_entry {
  const char *name = nullptr;
  enum ggml_type type = GGML_TYPE_F32;
  int n_dims = 0;
  int64_t ne[GGML_MAX_DIMS] = {};
  int64_t n_elements = 0;
  size_t n_bytes = 0;
  size_t offset = 0;
  size_t file_offset = 0;
  size_t block_size = 1;
  size_t type_size = 1;
  tensor_layout layout;
};

// compute a 2D/3D layout from a tensor shape
tensor_layout compute_layout(const tensor_entry &tensor);

// rectangular tile of dequantized float values
struct tensor_tile {
  size_t x = 0;
  size_t y = 0;
  size_t slice = 0;
  size_t width = 0;
  size_t height = 0;
  size_t valid = 0;
  float min = 0.0f;
  float max = 0.0f;
  std::vector<float> values;
  std::vector<uint8_t> mask;
};

// extract a rectangular tile of values from a tensor slice
bool tensor_read_tile(const mapped_file &file, const tensor_entry &tensor,
                      size_t slice, size_t x, size_t y, size_t width,
                      size_t height, tensor_tile &out, std::string &error);

// per-slice statistics (cached after first computation)
struct slice_stats {
  bool computed = false;
  size_t valid = 0;
  float min = 0.0f;
  float max = 0.0f;
  float p_lower = 0.0f;
  float p_upper = 0.0f;
};

// compute statistics for a tensor slice using reservoir sampling
bool tensor_slice_stats(const mapped_file &file, const tensor_entry &tensor,
                        size_t slice, slice_stats &out, std::string &error);

// histogram result
struct tensor_histogram {
  size_t slice = 0;
  uint64_t total = 0;
  uint64_t max_bin = 0;
  uint64_t clipped_lo = 0;
  uint64_t clipped_hi = 0;
  uint64_t zero_count = 0;
  float range_min = 0.0f;
  float range_max = 0.0f;
  std::vector<uint64_t> bins;
};

// compute a histogram for a tensor slice
bool tensor_slice_histogram(const mapped_file &file, const tensor_entry &tensor,
                            size_t slice, size_t bin_count,
                            tensor_histogram &out, std::string &error);

// single element details (for tooltip on click)
struct element_details {
  size_t element_index = 0;
  size_t element_count = 0;
  size_t block_index = 0;
  size_t index_in_block = 0;
  size_t tensor_byte_offset = 0;
  size_t file_byte_offset = 0;
  float value = 0.0f;
  bool valid = false;
};

// get details for a single tensor element
bool tensor_element_at(const mapped_file &file, const tensor_entry &tensor,
                       size_t slice, size_t x, size_t y, element_details &out,
                       std::string &error);
