/*
 * BTX valuation model reference implementation
 * Version: 1.8.0
 * Date: 2026-08-24
 *
 * Build:
 *   cc -std=c99 -O2 -Wall -Wextra -pedantic btx-valuation-model-v1.8.c -lm -o btx-model
 *
 * Run with canonical defaults:
 *   ./btx-model
 *
 * Run with custom live inputs:
 *   ./btx-model <btc_price_usd> <btc_hashrate_hps> <network_matmul_rate_hps> [btx_circulating_supply] [btx_block_height] [prior_effective_network_matmul_rate_hps] [elapsed_seconds] [network_matmul_rate_reference_hps] [network_matmul_rate_reference_months]
 *
 * v1.8.0 uses era-indexed linear security equivalence:
 *   security_equiv_hashrate_hps = matmul_security_weight(h) * network_matmul_rate_hps
   matmul_security_weight(h) = matmul_security_weight_v3               if h < 185000
   matmul_security_weight(h) = matmul_security_weight_v3 * matmul_v47_omega otherwise
 *   btx_security_percent = 100 * security_equiv_hashrate_hps / btc_hashrate_hps
 *   model_compute_floor_usd = compute_floor_usd * btx_supply_multiplier
 *
 * The effective MatMul release envelope remains printed for audit, but it is
 * not a headline valuation or Forward Market Price input.
 * When a valid recent MatMul-rate reference is supplied, the Forward Market
 * Price applies the same bounded trend overlay as btxprice.com.
 *
 * Equivalence invariant:
 *   if security_equiv_hashrate_hps == btc_hashrate_hps, then
 *   btx_security_percent == 100 and compute_floor_usd == btc_price_usd.
 *
 * The 12-month Forward Market Price is a single probability-weighted expected
 * market-cap path. Bear, base, and bull paths use linear 12-month
 * compute-adoption growth factors of 8x, 24x, and 80x. Scenario caps are
 * incremental BTX-as-percent-of-Bitcoin security headroom above the current
 * chain-observed level. That keeps bear/base/bull paths active after a live
 * compute surge exceeds older absolute terminal caps, while still bounding
 * each scenario's additional adoption. The forward token price divides that
 * market cap by projected BTX supply at the horizon using the 90-second block
 * schedule.
 *
 * Nonce-rate audit boundary:
 *   BTX v0.32.x activates nonce-seed v2 at block 125,000, nonce-seed v3
 *   parent-MTP binding at block 130,500, and v0.32.11/v3-fix guidance at
 *   block 132,000. The public btx_nonce_rate_raw audit field retains the legacy
 *   shared-seed raw-nonce model through block 124,999 and recalculates block
 *   125,000+ rows with a height-weighted one-week protocol-era transition.
 *   The v3 and v0.32.11 boundaries change seed binding/solver correctness,
 *   not the Bitcoin-style chainwork/sec chart or valuation input.
 *   The public compute field in this reference remains network_matmul_rate_hps.
 */

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

typedef struct {
  const char *label;
  int months;
  double forward_market_price_usd;
  double sats;
  double forward_market_cap;
  double fully_diluted_valuation;
  double projected_supply;
  int projected_blocks;
  double security_percent;
} ForwardPoint;

typedef struct {
  const char *key;
  const char *label;
  double probability;
  double growth_12m;
  double security_cap_percent;
  double half_life_months;
} Scenario;

static const double MATMUL_SECURITY_WEIGHT = 45251427826.03048142932710193;
static const double RISK_INDEX = 0.635;
static const double RISK_SPOT_WEIGHT = 0.25;
static const double RISK_LONG_WEIGHT = 0.75;
static const double RISK_HALF_LIFE_MONTHS = 6.0;
static const Scenario SCENARIOS[] = {
    {"bear", "Bear", 0.35, 8.0, 2.50, 9.0},
    {"base", "Base", 0.50, 24.0, 10.00, 6.0},
    {"bull", "Bull", 0.15, 80.0, 35.00, 4.0}};

static const double BTX_MAX_SUPPLY = 21000000.0;
static const double BTX_BLOCK_TIME_SECONDS = 90.0;
static const int BTX_MATMUL_WINDOW_BLOCKS = 6720;
static const double BTX_MATMUL_WINDOW_SECONDS = 604800.0;
static const char *BTX_MATMUL_METHOD = "network_matmul_rate_hps=getnetworkhashps(6720)";
static const int BTX_NONCE_SEED_V2_ACTIVATION_HEIGHT = 125000;
static const int BTX_NONCE_SEED_V3_ACTIVATION_HEIGHT = 130500;
static const int BTX_V03211_ACTIVATION_HEIGHT = 132000;
static const int BTX_MATMUL_V47_ACTIVATION_HEIGHT = 185000;
/* Realized compact-nBits Ω = target(185000)/target(184999). */
static const double MATMUL_V47_OMEGA = 196423.7726216227;
static const double NETWORK_MATMUL_ANCHOR_HPS = 554455.9237024327;
static const double DEPRECATED_RAW_NONCE_AUDIT_NPS =
    103935054.7395844930974550080;
static const double MATMUL_RELEASE_HALF_LIFE_SECONDS = 604800.0;
static const double FORWARD_TREND_UP_WEIGHT = 0.35;
static const double FORWARD_TREND_DOWN_WEIGHT = 0.55;
static const double FORWARD_TREND_UP_CAP_MONTHLY_LOG = 0.45;
static const double FORWARD_TREND_DOWN_CAP_MONTHLY_LOG = 0.35;

static const double SUPPLY_CIRCULATING_ANCHOR = 21000000.0;
static const double FLOAT_ALPHA = 0.08;
static const double FLOAT_FLOOR = 0.05;
static const double FLOAT_MULTIPLIER_MIN = 0.90;
static const double FLOAT_MULTIPLIER_MAX = 1.25;
static const double SUPPLY_MULTIPLIER_MIN = 0.85;
static const double SUPPLY_MULTIPLIER_MAX = 1.25;
static const double SUPPLY_UNLOCK_DRAG_EXPONENT = 0.05;

static double clamp(double x, double lo, double hi) {
  if (x < lo) return lo;
  if (x > hi) return hi;
  return x;
}

static double btx_supply_after_blocks(double blocks) {
  double remaining = blocks;
  double subsidy = 20.0;
  double issued = 0.0;

  while (remaining > 0.0 && subsidy >= 0.00000001 && issued < BTX_MAX_SUPPLY) {
    double mined = remaining < 525000.0 ? remaining : 525000.0;
    issued += mined * subsidy;
    remaining -= mined;
    subsidy /= 2.0;
  }

  return issued > BTX_MAX_SUPPLY ? BTX_MAX_SUPPLY : issued;
}

static double projected_btx_supply(double height, int months) {
  if (height < 0.0) return -1.0;

  double blocks_now = height + 1.0;
  double blocks_to_add = round((months * 30.4375 * 86400.0) / BTX_BLOCK_TIME_SECONDS);
  return btx_supply_after_blocks(blocks_now + blocks_to_add);
}

static int projected_blocks(int months) {
  return (int)round((months * 30.4375 * 86400.0) / BTX_BLOCK_TIME_SECONDS);
}

static double matmul_security_weight_at(int height) {
  if (height >= BTX_MATMUL_V47_ACTIVATION_HEIGHT)
    return MATMUL_SECURITY_WEIGHT * MATMUL_V47_OMEGA;
  return MATMUL_SECURITY_WEIGHT;
}

static double security_equiv_hashrate_hps(double network_matmul_rate_hps, int height) {
  return matmul_security_weight_at(height) * network_matmul_rate_hps;
}

static double btx_security_percent(double btc_hashrate_hps,
                                   double network_matmul_rate_hps,
                                   int height) {
  return 100.0 * security_equiv_hashrate_hps(network_matmul_rate_hps, height) /
         btc_hashrate_hps;
}

static double compute_floor_usd(double btc_price_usd,
                                double btc_hashrate_hps,
                                double network_matmul_rate_hps,
                                int height) {
  return btc_price_usd *
         (security_equiv_hashrate_hps(network_matmul_rate_hps, height) /
          btc_hashrate_hps);
}

static double release_retention(double elapsed_seconds) {
  double elapsed = elapsed_seconds > 0.0 ? elapsed_seconds : 0.0;
  return pow(2.0, -elapsed / MATMUL_RELEASE_HALF_LIFE_SECONDS);
}

static double effective_network_matmul_rate(double network_matmul_rate_hps,
                                            double prior_effective_network_matmul_rate_hps,
                                            double elapsed_seconds) {
  if (prior_effective_network_matmul_rate_hps <= 0.0 ||
      network_matmul_rate_hps >= prior_effective_network_matmul_rate_hps) {
    return network_matmul_rate_hps;
  }

  double retention = release_retention(elapsed_seconds);
  double effective =
      network_matmul_rate_hps +
      (prior_effective_network_matmul_rate_hps - network_matmul_rate_hps) *
          retention;

  return effective > network_matmul_rate_hps ? effective : network_matmul_rate_hps;
}

static double supply_multiplier(double btx_circulating_supply, double btx_height) {
  double circulating =
      btx_circulating_supply > 0.0 ? btx_circulating_supply : BTX_MAX_SUPPLY;
  if (circulating > BTX_MAX_SUPPLY) circulating = BTX_MAX_SUPPLY;

  double float_ratio = clamp(circulating / BTX_MAX_SUPPLY, FLOAT_FLOOR, 1.0);
  double anchor_float =
      clamp(SUPPLY_CIRCULATING_ANCHOR / BTX_MAX_SUPPLY, FLOAT_FLOOR, 1.0);

  double float_multiplier =
      clamp(pow(anchor_float / float_ratio, FLOAT_ALPHA),
            FLOAT_MULTIPLIER_MIN,
            FLOAT_MULTIPLIER_MAX);

  double projected = projected_btx_supply(btx_height, 12);
  double unlock_overhang = 0.0;

  if (projected > circulating) {
    double denominator = fmax(circulating, FLOAT_FLOOR * BTX_MAX_SUPPLY);
    unlock_overhang = (projected - circulating) / denominator;
  }

  double unlock_drag = pow(1.0 + unlock_overhang, -SUPPLY_UNLOCK_DRAG_EXPONENT);

  return clamp(float_multiplier * unlock_drag,
               SUPPLY_MULTIPLIER_MIN,
               SUPPLY_MULTIPLIER_MAX);
}

static double model_compute_floor_usd(double btc_price_usd,
                                      double btc_hashrate_hps,
                                      double network_matmul_rate_hps,
                                      double supply_multiplier_value,
                                      int height) {
  return compute_floor_usd(btc_price_usd,
                           btc_hashrate_hps,
                           network_matmul_rate_hps,
                           height) *
         supply_multiplier_value;
}

static double risk_multiplier(int months) {
  double closure = 1.0 - pow(0.5, ((double)months) / RISK_HALF_LIFE_MONTHS);
  double weight =
      RISK_SPOT_WEIGHT + (RISK_LONG_WEIGHT - RISK_SPOT_WEIGHT) * closure;
  return 1.0 + RISK_INDEX * weight;
}

static double adoption_progress(int months, double half_life_months) {
  if (months <= 0) return 0.0;
  double capped = months > 12 ? 12.0 : (double)months;
  if (half_life_months <= 0.0) return capped / 12.0;
  double numerator = 1.0 - pow(0.5, capped / half_life_months);
  double denominator = 1.0 - pow(0.5, 12.0 / half_life_months);
  return numerator / denominator;
}

static double trend_multiplier(double current_matmul_rate_hps,
                               double reference_matmul_rate_hps,
                               double reference_months,
                               int months) {
  if (months <= 0 ||
      current_matmul_rate_hps <= 0.0 ||
      reference_matmul_rate_hps <= 0.0 ||
      reference_months <= 0.0) {
    return 1.0;
  }

  double trend_rate = log(current_matmul_rate_hps / reference_matmul_rate_hps) /
                      reference_months;
  double effective_rate;

  if (trend_rate >= 0.0) {
    double capped =
        trend_rate < FORWARD_TREND_UP_CAP_MONTHLY_LOG
            ? trend_rate
            : FORWARD_TREND_UP_CAP_MONTHLY_LOG;
    effective_rate = capped * FORWARD_TREND_UP_WEIGHT;
  } else {
    double capped =
        trend_rate > -FORWARD_TREND_DOWN_CAP_MONTHLY_LOG
            ? trend_rate
            : -FORWARD_TREND_DOWN_CAP_MONTHLY_LOG;
    effective_rate = capped * FORWARD_TREND_DOWN_WEIGHT;
  }

  return exp(effective_rate * months);
}

static double scenario_security_percent(double current_security_percent,
                                        Scenario scenario,
                                        int months,
                                        double terminal_trend_multiplier) {
  if (months <= 0) return current_security_percent;
  if (current_security_percent <= 0.0) return 0.0;

  double terminal_growth = scenario.growth_12m * terminal_trend_multiplier;
  double growth_headroom =
      current_security_percent * fmax(terminal_growth - 1.0, 0.0);
  double terminal =
      current_security_percent +
      (growth_headroom < scenario.security_cap_percent
           ? growth_headroom
           : scenario.security_cap_percent);

  if (months >= 12) return terminal;

  double progress = adoption_progress(months, scenario.half_life_months);
  return current_security_percent *
         pow(terminal / current_security_percent, progress);
}

static double btx_security_percent_forward(double current_security_percent,
                                           int months,
                                           double terminal_trend_multiplier) {
  double expected = 0.0;

  for (size_t i = 0; i < sizeof(SCENARIOS) / sizeof(SCENARIOS[0]); i++) {
    expected += SCENARIOS[i].probability *
                scenario_security_percent(current_security_percent,
                                          SCENARIOS[i],
                                          months,
                                          terminal_trend_multiplier);
  }

  return expected;
}

static ForwardPoint forward_point(const char *label,
                                  int months,
                                  double btc_price_usd,
                                  double current_security_percent,
                                  double supply_multiplier_value,
                                  double btx_circulating_supply,
                                  double btx_block_height,
                                  double terminal_trend_multiplier) {
  double expected_security =
      btx_security_percent_forward(current_security_percent,
                                   months,
                                   terminal_trend_multiplier);
  double circulating =
      btx_circulating_supply > 0.0 ? btx_circulating_supply : BTX_MAX_SUPPLY;
  double horizon_supply =
      months == 0 ? circulating : projected_btx_supply(btx_block_height, months);
  if (horizon_supply <= 0.0 || horizon_supply < circulating) {
    horizon_supply = circulating;
  }
  double forward_market_cap = btc_price_usd * (expected_security / 100.0) *
                              supply_multiplier_value * risk_multiplier(months) *
                              circulating;
  double usd = forward_market_cap / horizon_supply;
  double sats = usd / (btc_price_usd / 100000000.0);

  ForwardPoint point = {
      label,
      months,
      usd,
      sats,
      forward_market_cap,
      usd * BTX_MAX_SUPPLY,
      horizon_supply,
      projected_blocks(months),
      expected_security};

  return point;
}

int main(int argc, char **argv) {
  double btc_price_usd = argc > 1 ? atof(argv[1]) : 75510.0;
  double btc_hashrate_hps = argc > 2 ? atof(argv[2]) : 988470643627111900000.0;
  double network_matmul_rate_hps =
      argc > 3 ? atof(argv[3]) : NETWORK_MATMUL_ANCHOR_HPS;
  double btx_circulating_supply = argc > 4 ? atof(argv[4]) : 2178700.0;
  double btx_block_height = argc > 5 ? atof(argv[5]) : 108934.0;
  double prior_effective_network_matmul_rate_hps =
      argc > 6 ? atof(argv[6]) : network_matmul_rate_hps;
  double elapsed_seconds = argc > 7 ? atof(argv[7]) : 0.0;
  double network_matmul_rate_reference_hps = argc > 8 ? atof(argv[8]) : 0.0;
  double network_matmul_rate_reference_months = argc > 9 ? atof(argv[9]) : 0.0;
  double terminal_trend =
      trend_multiplier(network_matmul_rate_hps,
                       network_matmul_rate_reference_hps,
                       network_matmul_rate_reference_months,
                       12);

  double seh = security_equiv_hashrate_hps(network_matmul_rate_hps, (int)btx_block_height);
  double security_percent =
      btx_security_percent(btc_hashrate_hps, network_matmul_rate_hps, (int)btx_block_height);
  double effective_rate =
      effective_network_matmul_rate(network_matmul_rate_hps,
                                    prior_effective_network_matmul_rate_hps,
                                    elapsed_seconds);
  double floor_usd =
      compute_floor_usd(btc_price_usd, btc_hashrate_hps, network_matmul_rate_hps, (int)btx_block_height);
  double f_supply = supply_multiplier(btx_circulating_supply, btx_block_height);
  double model_floor =
      model_compute_floor_usd(btc_price_usd,
                              btc_hashrate_hps,
                              network_matmul_rate_hps,
                              f_supply,
                              (int)btx_block_height);
  double spot = model_floor * risk_multiplier(0);
  ForwardPoint m12 =
      forward_point("12m",
                    12,
                    btc_price_usd,
                    security_percent,
                    f_supply,
                    btx_circulating_supply,
                    btx_block_height,
                    terminal_trend);

  printf("BTX valuation model v1.8.0\n");
  printf("btc_price_usd=%.8f\n", btc_price_usd);
  printf("btc_hashrate_hps=%.4e\n", btc_hashrate_hps);
  printf("network_matmul_rate_method=%s\n", BTX_MATMUL_METHOD);
  printf("nonce_seed_v2_activation_height=%d\n",
         BTX_NONCE_SEED_V2_ACTIVATION_HEIGHT);
  printf("nonce_seed_v3_activation_height=%d\n",
         BTX_NONCE_SEED_V3_ACTIVATION_HEIGHT);
  printf("v03211_activation_height=%d\n", BTX_V03211_ACTIVATION_HEIGHT);
  printf("matmul_v47_activation_height=%d\n", BTX_MATMUL_V47_ACTIVATION_HEIGHT);
  printf("matmul_v47_omega=%.10f\n", MATMUL_V47_OMEGA);
  printf("matmul_security_weight=%.14f\n", matmul_security_weight_at((int)btx_block_height));
  printf("network_matmul_rate_window_blocks=%d\n", BTX_MATMUL_WINDOW_BLOCKS);
  printf("network_matmul_rate_window_seconds=%.0f\n", BTX_MATMUL_WINDOW_SECONDS);
  printf("network_matmul_rate_hps=%.8f\n", network_matmul_rate_hps);
  printf("network_matmul_rate_reference_hps=%.8f\n",
         network_matmul_rate_reference_hps);
  printf("network_matmul_rate_reference_months=%.8f\n",
         network_matmul_rate_reference_months);
  printf("forward_trend_multiplier_12m=%.12f\n", terminal_trend);
  printf("matmul_security_weight=%.14f\n", MATMUL_SECURITY_WEIGHT);
  printf("deprecated_raw_nonce_audit_nps=%.8f\n",
         DEPRECATED_RAW_NONCE_AUDIT_NPS);
  printf("security_equiv_hashrate_hps=%.8e\n", seh);
  printf("btx_security_percent=%.12f\n", security_percent);
  printf("compute_floor_usd=%.12f\n", floor_usd);
  printf("prior_effective_network_matmul_rate_hps=%.8f\n",
         prior_effective_network_matmul_rate_hps);
  printf("matmul_release_elapsed_seconds=%.0f\n", elapsed_seconds);
  printf("matmul_release_retention=%.12f\n", release_retention(elapsed_seconds));
  printf("matmul_release_half_life_seconds=%.0f\n",
         MATMUL_RELEASE_HALF_LIFE_SECONDS);
  printf("effective_network_matmul_rate_hps=%.8f\n", effective_rate);
  printf("btx_supply_multiplier=%.8f\n", f_supply);
  printf("model_compute_floor_usd=%.12f\n", model_floor);
  printf("spot_usd=%.12f\n", spot);
  printf("forward_market_price_usd=%.12f\n", m12.forward_market_price_usd);
  printf("forward_market_cap=%.2f\n", m12.forward_market_cap);
  printf("forward_projected_supply=%.8f\n", m12.projected_supply);
  printf("forward_projected_blocks=%d\n", m12.projected_blocks);
  printf("btx_security_percent_12m=%.12f\n", m12.security_percent);

  printf("\nforward_scenarios\n");
  printf("scenario,probability,growth_12m,security_headroom_percent,half_life_months,security_percent_12m\n");

  for (size_t i = 0; i < sizeof(SCENARIOS) / sizeof(SCENARIOS[0]); i++) {
    printf("%s,%.6f,%.6f,%.6f,%.6f,%.12f\n",
           SCENARIOS[i].key,
           SCENARIOS[i].probability,
           SCENARIOS[i].growth_12m,
           SCENARIOS[i].security_cap_percent,
           SCENARIOS[i].half_life_months,
           scenario_security_percent(security_percent,
                                     SCENARIOS[i],
                                     12,
                                     terminal_trend));
  }

  printf("\nforward_curve\n");
  printf("horizon,months,forward_market_price_usd,btx_security_percent_forward,sats,forward_market_cap,fully_diluted_valuation,projected_supply,projected_blocks\n");

  for (int months = 0; months <= 12; months++) {
    char label[8];

    if (months == 0) {
      snprintf(label, sizeof(label), "now");
    } else {
      snprintf(label, sizeof(label), "%dm", months);
    }

    ForwardPoint forecast =
        forward_point(label,
                      months,
                      btc_price_usd,
                      security_percent,
                      f_supply,
                      btx_circulating_supply,
                      btx_block_height,
                      terminal_trend);

    printf("%s,%d,%.12f,%.12f,%.6f,%.2f,%.2f,%.8f,%d\n",
           forecast.label,
           forecast.months,
           forecast.forward_market_price_usd,
           forecast.security_percent,
           forecast.sats,
           forecast.forward_market_cap,
           forecast.fully_diluted_valuation,
           forecast.projected_supply,
           forecast.projected_blocks);
  }

  return 0;
}
