// field_test.el — Proof of concept: Hebbian field model
//
// Tests the core mechanics:
//   1. Nodes with 2D semantic positions and temporal coordinates
//   2. Edges with weights that grow via co-activation (Hebb's rule)
//   3. Spreading activation with path strength
//   4. Temporal decay in path strength
//   5. Epistemic confidence = node confidence * path strength
//
// No storage — pure in-memory demonstration using print output.

// ── Math helpers ──────────────────────────────────────────────────────────────

fn clamp_f(v: Float, lo: Float, hi: Float) -> Float {
    if v < lo {
        return lo
    }
    if v > hi {
        return hi
    }
    return v
}

// L2 distance squared — no sqrt needed for proximity comparison
fn dist_sq(ax: Float, ay: Float, bx: Float, by: Float) -> Float {
    let dx: Float = ax - bx
    let dy: Float = ay - by
    return dx * dx + dy * dy
}

// Proximity score: 1 / (1 + dist_sq) — range (0, 1], closer = higher
fn proximity(ax: Float, ay: Float, bx: Float, by: Float) -> Float {
    let d: Float = dist_sq(ax, ay, bx, by)
    return 1.0 / (1.0 + d)
}

// Linear temporal decay: 1.0 at t=0, decaying toward 0
// decay_rate: fraction lost per time unit
fn temporal_decay(age: Float, decay_rate: Float) -> Float {
    let d: Float = 1.0 - decay_rate * age
    return clamp_f(d, 0.0, 1.0)
}

// ── Hebbian learning ──────────────────────────────────────────────────────────

// New edge weight after co-activation event
// w_new = clamp(w + lr * a_i * a_j, 0, 1)
fn hebbian_update(weight: Float, act_i: Float, act_j: Float, lr: Float) -> Float {
    let delta: Float = lr * act_i * act_j
    return clamp_f(weight + delta, 0.0, 1.0)
}

// Edge decay between activations
// w_new = w * (1 - decay_rate)
fn edge_decay(weight: Float, decay_rate: Float) -> Float {
    return clamp_f(weight * (1.0 - decay_rate), 0.0, 1.0)
}

// ── Path strength ─────────────────────────────────────────────────────────────

// Path strength = edge_weight * temporal_decay(node_age)
// This is the confidence qualifier on a retrieval result
fn path_strength(edge_weight: Float, node_age: Float, decay_rate: Float) -> Float {
    let td: Float = temporal_decay(node_age, decay_rate)
    return edge_weight * td
}

// Epistemic confidence = node_confidence * path_strength
fn epistemic_confidence(node_confidence: Float, ps: Float) -> Float {
    return node_confidence * ps
}

// ── Simulation ────────────────────────────────────────────────────────────────

fn run_test() -> String {
    println("=== Engram Field Model — Proof of Concept ===")
    println("")

    // ── Nodes ──
    // Each node: id, label, semantic position (x, y), temporal coordinate, confidence
    // Semantic space: 2D for demonstration
    //   x=0..1: concrete←→abstract
    //   y=0..1: negative←→positive valence

    println("── Nodes ──────────────────────────────────────")
    println("A: 'patient has fever'         pos=(0.2, 0.4)  t=100")
    println("B: 'influenza'                 pos=(0.3, 0.5)  t=90")
    println("C: 'drug interaction warning'  pos=(0.6, 0.3)  t=10   (old, unactivated)")
    println("D: 'ibuprofen'                 pos=(0.65, 0.3) t=10   (old, unactivated)")
    println("")

    // Semantic positions
    let ax: Float = 0.2
    let ay: Float = 0.4
    let bx: Float = 0.3
    let by: Float = 0.5
    let cx: Float = 0.6
    let cy: Float = 0.3
    let dx_pos: Float = 0.65
    let dy_pos: Float = 0.3

    // Initial proximity (latent gradient — implicit from positions)
    let prox_ab: Float = proximity(ax, ay, bx, by)
    let prox_ac: Float = proximity(ax, ay, cx, cy)
    let prox_cd: Float = proximity(cx, cy, dx_pos, dy_pos)

    println("── Initial latent gradients (proximity) ───────")
    println("A↔B proximity: " + float_to_str(prox_ab) + "  (semantically close — fever/flu)")
    println("A↔C proximity: " + float_to_str(prox_ac) + "  (semantically distant)")
    println("C↔D proximity: " + float_to_str(prox_cd) + "  (close — drug interaction/ibuprofen)")
    println("")

    // ── Initial edge weights (all start near zero — no co-activation yet) ──
    let w_ab: Float = 0.0
    let w_ac: Float = 0.0
    let w_cd: Float = 0.0

    println("── Initial edge weights ────────────────────────")
    println("A→B: " + float_to_str(w_ab) + "  (no co-activation yet)")
    println("A→C: " + float_to_str(w_ac))
    println("C→D: " + float_to_str(w_cd))
    println("")

    // ── Co-activation events ──
    // The doctor CGI processes a patient with fever.
    // A (fever) and B (influenza) co-activate — the diagnosis fires both.
    // Learning rate: 0.3

    let lr: Float = 0.3
    let act_strength: Float = 1.0   // full activation

    println("── Co-activation event 1: patient with fever → flu diagnosis ──")
    let w_ab_1: Float = hebbian_update(w_ab, act_strength, act_strength, lr)
    println("A and B fire together (strength=1.0)")
    println("A→B weight: " + float_to_str(w_ab) + " → " + float_to_str(w_ab_1))
    println("")

    println("── Co-activation event 2: another flu case ──")
    let w_ab_2: Float = hebbian_update(w_ab_1, act_strength, act_strength, lr)
    println("A and B fire together again")
    println("A→B weight: " + float_to_str(w_ab_1) + " → " + float_to_str(w_ab_2))
    println("")

    println("── Co-activation event 3: third flu case ──")
    let w_ab_3: Float = hebbian_update(w_ab_2, act_strength, act_strength, lr)
    println("A and B fire together again")
    println("A→B weight: " + float_to_str(w_ab_2) + " → " + float_to_str(w_ab_3))
    println("")

    // C and D have never been activated in this context — weights stay near zero
    // (In practice, proximity means a latent gradient exists, but no learned edge yet)

    // ── Query: activate A (fever), what spreads? ──
    println("── Query: activate A (fever) ───────────────────")
    println("Spreading activation from A...")
    println("")

    // Decay rates
    let temporal_decay_rate: Float = 0.005   // per time unit
    let current_t: Int = 200

    // Node ages (current_t - node_t)
    let age_b: Float = 110.0    // t=90, current=200
    let age_c: Float = 190.0    // t=10, current=200
    let age_d: Float = 190.0    // t=10, current=200

    // Path strength to B: strong edge, recently relevant
    let ps_b: Float = path_strength(w_ab_3, age_b, temporal_decay_rate)
    let conf_b: Float = epistemic_confidence(0.9, ps_b)

    // Path strength to C: no learned edge — only latent proximity gradient
    // Spreading activation from A can weakly reach C via proximity alone
    let latent_ac: Float = prox_ac * 0.1   // proximity contributes small initial signal
    let ps_c: Float = path_strength(latent_ac, age_c, temporal_decay_rate)
    let conf_c: Float = epistemic_confidence(0.9, ps_c)

    // Path strength to D via C: chain of weak signals
    let ps_d: Float = path_strength(latent_ac * prox_cd * 0.1, age_d, temporal_decay_rate)
    let conf_d: Float = epistemic_confidence(0.9, ps_d)

    println("Result: B (influenza)")
    println("  Edge weight:     " + float_to_str(w_ab_3))
    println("  Node age:        " + float_to_str(age_b) + " time units")
    println("  Temporal decay:  " + float_to_str(temporal_decay(age_b, temporal_decay_rate)))
    println("  Path strength:   " + float_to_str(ps_b))
    println("  Confidence:      " + float_to_str(conf_b))
    println("  → STRONG: B surfaces with high confidence")
    println("")

    println("Result: C (drug interaction warning)")
    println("  Edge weight:     " + float_to_str(latent_ac) + "  (latent only — never co-activated)")
    println("  Node age:        " + float_to_str(age_c) + " time units")
    println("  Temporal decay:  " + float_to_str(temporal_decay(age_c, temporal_decay_rate)))
    println("  Path strength:   " + float_to_str(ps_c))
    println("  Confidence:      " + float_to_str(conf_c))
    println("  → WEAK: C is distant and old — attenuated path triggers refresh signal")
    println("")

    println("Result: D (ibuprofen) via C")
    println("  Path strength:   " + float_to_str(ps_d))
    println("  Confidence:      " + float_to_str(conf_d))
    println("  → VERY WEAK: chain of attenuated edges")
    println("")

    // ── Refresh trigger ──
    println("── Attenuation trigger ─────────────────────────")
    let threshold: Float = 0.2
    println("Confidence threshold: " + float_to_str(threshold))
    if conf_c < threshold {
        println("C is below threshold (" + float_to_str(conf_c) + " < " + float_to_str(threshold) + ")")
        println("→ Trigger: 'drug interaction warning node found but path is weak.")
        println("           Last activated " + float_to_str(age_c) + " time units ago.")
        println("           Recommend fetching current information before acting.'")
    }
    println("")

    // ── After refresh: C and D co-activate with A ──
    println("── Refresh: doctor looks up drug interactions ──")
    println("A, C, D all co-activate during research")
    let w_ac_new: Float = hebbian_update(0.0, act_strength, act_strength, lr)
    let w_cd_new: Float = hebbian_update(0.0, act_strength, act_strength, lr)
    let age_c_new: Float = 0.0    // just activated
    let age_d_new: Float = 0.0

    let ps_c_new: Float = path_strength(w_ac_new, age_c_new, temporal_decay_rate)
    let conf_c_new: Float = epistemic_confidence(0.9, ps_c_new)

    println("A→C weight after refresh: " + float_to_str(w_ac_new))
    println("C→D weight after refresh: " + float_to_str(w_cd_new))
    println("C confidence after refresh: " + float_to_str(conf_c_new))
    println("→ Edges strengthened. Drug interaction now reachable with high confidence.")
    println("")

    println("=== Result ===")
    println("Perfect memory: all nodes present throughout.")
    println("Calibrated confidence: B (flu) high, C/D (drug interaction) low until refreshed.")
    println("Self-correcting: attenuation triggered fetch, fetch strengthened edges.")
    println("The field works.")

    return "ok"
}

let result: String = run_test()
