#ifndef PROBOL_STDLIB_H
#define PROBOL_STDLIB_H

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

/*============================================================================
  Configuration – adjust for target RAM / precision
============================================================================*/
#ifndef PROBOL_MAX_STATES
#define PROBOL_MAX_STATES 256      /* max distinct values in a probability tensor */
#endif

#ifndef PROBOL_FIXED_POINT_SHIFT
#define PROBOL_FIXED_POINT_SHIFT 12 /* 12 bits fractional = 1/4096 precision */
#endif

#ifndef PROBOL_CCT_WINDOW
#define PROBOL_CCT_WINDOW 30       /* look‑ahead days for entropy gradient */
#endif

/*============================================================================
  Basic type definitions
============================================================================*/
typedef int64_t prob_fixed_t;       /* fixed‑point decimal: value * 2^SHIFT */

/* Probability tensor – explicit list of (value, probability) pairs.
   Probabilities are also fixed‑point, sum = 1.0 exactly (scale = 2^SHIFT). */
typedef struct {
    prob_fixed_t values[PROBOL_MAX_STATES];
    prob_fixed_t probs[PROBOL_MAX_STATES];
    int          count;
} ProbTensor;

/* Parametric distribution (Normal / Gaussian) */
typedef struct {
    prob_fixed_t mu;      /* mean */
    prob_fixed_t sigma;   /* standard deviation (>0) */
} ProbNormal;

/* GARCH(1,1) parameters */
typedef struct {
    prob_fixed_t omega;
    prob_fixed_t alpha;
    prob_fixed_t beta;
    prob_fixed_t init_var;
} GARCH11;

/* Copula types */
typedef enum {
    COPULA_GAUSSIAN,
    COPULA_T,
    COPULA_CLAYTON,
    COPULA_GUMBEL,
    COPULA_DCC_GARCH,
    COPULA_REGIME_SWITCH
} CopulaType;

/* Gaussian copula with correlation matrix (dense, max 32 assets) */
#define PROBOL_MAX_ASSETS 32
typedef struct {
    int            dim;
    prob_fixed_t   corr[PROBOL_MAX_ASSETS][PROBOL_MAX_ASSETS];
    prob_fixed_t   cholesky[PROBOL_MAX_ASSETS][PROBOL_MAX_ASSETS];
} CopulaGaussian;

/* t‑copula with ν degrees of freedom */
typedef struct {
    CopulaGaussian base;
    int            df;
} CopulaT;

/* Clayton / Gumbel copulas (single parameter θ) */
typedef struct {
    prob_fixed_t theta;
} CopulaArchimedean;

/* DCC‑GARCH parameters */
typedef struct {
    prob_fixed_t a, b;
    prob_fixed_t initial_rho;
    prob_fixed_t *var_series;   /* GARCH variances per asset, size = dim */
} CopulaDCC;

/* Regime‑switching copula with two regimes */
typedef struct {
    prob_fixed_t trans_matrix[2][2];   /* P(regime_j | regime_i) */
    CopulaGaussian regime_copula[2];
} CopulaRegimeSwitch;

/* Union of all copula types */
typedef struct {
    CopulaType type;
    union {
        CopulaGaussian        gaussian;
        CopulaT               t;
        CopulaArchimedean     arch;
        CopulaDCC             dcc;
        CopulaRegimeSwitch    regime;
    };
} Copula;

/* Time series state – used by SIMULATEP */
typedef struct {
    prob_fixed_t value;          /* current simulated value (collapsed) */
    prob_fixed_t variance;       /* GARCH variance (if applicable) */
    int          regime;         /* current regime (0 or 1) */
} TimeSeriesState;

/* CCT collapse schedule – array of time steps where MEAS should be called */
typedef struct {
    int    collapse_points[256];
    int    num_collapses;
} CCTSchedule;

/*============================================================================
  Probability Tensor Primitives
============================================================================*/
void probol_init_tensor(ProbTensor *t);
void probol_add_state(ProbTensor *t, prob_fixed_t val, prob_fixed_t prob);
void probol_normalize(ProbTensor *t);          /* ensure probs sum to 1.0 */

/* Convolution (ADDP) – returns new tensor = A + B (combined distribution) */
void probol_add_tensors(const ProbTensor *A, const ProbTensor *B, ProbTensor *C);

/* Product (MULTIPLYP) – returns distribution of A * B */
void probol_multiply_tensors(const ProbTensor *A, const ProbTensor *B, ProbTensor *C);

/* Analytic quantile (QUANTILEP) – smallest value v such that P(X ≤ v) ≥ quantile */
prob_fixed_t probol_quantile(const ProbTensor *t, prob_fixed_t quantile);

/* Measure (collapse) – sample one value according to probabilities */
prob_fixed_t probol_measure(const ProbTensor *t);

/* Probability of condition (PROBP) – sum of probabilities where f(value) is true */
prob_fixed_t probol_prob_condition(const ProbTensor *t, bool (*condition)(prob_fixed_t));

/* Entropy of a tensor (used by CCT) */
prob_fixed_t probol_entropy(const ProbTensor *t);

/*============================================================================
  Parametric Distributions – create tensors from Normal, etc.
============================================================================*/
void probol_normal_to_tensor(const ProbNormal *n, ProbTensor *out, int num_bins);
void probol_gaussian(prob_fixed_t mu, prob_fixed_t sigma, ProbTensor *out);

/*============================================================================
  Copula Functions
============================================================================*/
void probol_copula_init_gaussian(CopulaGaussian *c, int dim);
void probol_copula_set_correlation(CopulaGaussian *c, int i, int j, prob_fixed_t rho);
void probol_copula_compute_cholesky(CopulaGaussian *c);  /* Cholesky decomposition */

/* Sample from a copula given uniform marginals U[0,1] (inverse CDF method) */
void probol_copula_sample(const Copula *c, const prob_fixed_t *uniforms, prob_fixed_t *correlated, int n);

/*============================================================================
  GARCH Volatility
============================================================================*/
void probol_garch_update(const GARCH11 *params, prob_fixed_t innovation, prob_fixed_t *variance);
prob_fixed_t probol_garch_simulate(const GARCH11 *params, int steps, prob_fixed_t *var_out);

/*============================================================================
  CCT Scheduler – detects when to insert MEAS operations
============================================================================*/
CCTSchedule probol_cct_schedule(const ProbTensor *initial_distribution,
                                int time_horizon,
                                prob_fixed_t (*dynamics)(int t, const ProbTensor *state));

/*============================================================================
  Time Series Simulation (SIMULATEP)
============================================================================*/
typedef struct {
    int            horizon;              /* days to simulate */
    int            num_assets;
    ProbTensor     *marginals;           /* per‑asset probability tensors */
    Copula         *copula;
    GARCH11        *garch_params;        /* optional, may be NULL */
    CCTSchedule    collapse_schedule;
} SimulationConfig;

void probol_simulate(const SimulationConfig *cfg,
                     TimeSeriesState *history,    /* output array of length horizon */
                     ProbTensor *final_tensor);   /* final distribution after horizon */

/*============================================================================
  I/O Extensions (compatible with probol_compiler's PRINT, COLOR, etc.)
============================================================================*/
void probol_print(const char *str);
void probol_print_tensor(const ProbTensor *t);
void probol_clear_screen(void);
void probol_set_color(int ansi_code);
void probol_gotoxy(int x, int y);
void probol_get_terminal_size(int *width, int *height);
char probol_getch(void);
void probol_raw_mode_enable(void);
void probol_raw_mode_disable(void);

/*============================================================================
  Fixed‑Point Arithmetic Helpers
============================================================================*/
#define FP_ONE   ((prob_fixed_t)(1 << PROBOL_FIXED_POINT_SHIFT))
#define FP_FROM(x)  ((prob_fixed_t)((x) * FP_ONE))
#define FP_TO_DOUBLE(x)  ((double)(x) / FP_ONE)

static inline prob_fixed_t fp_add(prob_fixed_t a, prob_fixed_t b) { return a + b; }
static inline prob_fixed_t fp_sub(prob_fixed_t a, prob_fixed_t b) { return a - b; }
static inline prob_fixed_t fp_mul(prob_fixed_t a, prob_fixed_t b) {
    return (prob_fixed_t)(((int64_t)a * b) >> PROBOL_FIXED_POINT_SHIFT);
}
static inline prob_fixed_t fp_div(prob_fixed_t a, prob_fixed_t b) {
    return (prob_fixed_t)((((int64_t)a) << PROBOL_FIXED_POINT_SHIFT) / b);
}

#endif /* PROBOL_STDLIB_H */