namespace DeepDrftPublic.Client.Services;
///
/// Holds the Mix visualizer's four continuous-control positions for the lifetime of the WASM app
/// instance. Scoped in DI, so it lives across SPA navigations within one listening session — open a
/// second mix and the sliders keep where you left them — but a fresh page load (F5) constructs a new
/// instance, resetting to defaults. That matches the spec's "persist within session, reset on fresh
/// load" without any cookie/localStorage round-trip (see mix-visualizer-webgl-renderer §3c).
///
/// One state object, four properties — not four sibling holders (Daniel's decided shape, spec §3c).
/// Each C#-side default mirrors a TS-side tuning anchor in MixVisualizer.ts; keep the two in sync, as
/// the existing DefaultVisibleSeconds / DEFAULT_VISIBLE_SECONDS pair does.
///
///
/// is the decoupling seam between the controls row and the visualizer bridge.
/// The controls component (a sibling of the backdrop in the page tree) only mutates this shared state
/// and raises ; the bridge component (MixWaveformVisualizer) subscribes
/// and pushes the affected uniform to the JS module. This keeps the JS module handle single-owned by
/// the bridge — no handle sharing, no service-locator, no cross-component interop.
///
///
public sealed class MixVisualizerControlState
{
///
/// Default opening window. Mirrors DEFAULT_VISIBLE_SECONDS in MixVisualizer.ts; keep the
/// two in sync (the TS owns the rendering anchors, this owns the C#-side session default).
///
public const double DefaultVisibleSeconds = 10.0;
// R2 TEMP (Phase 10 reframe Wave R2): the three controls below are re-routed to the new
// lava physics for Daniel's in-browser test — the JS handle setters map them as:
// Bubblyness → lava GRAVITY, Detach → lava HEAT, ColorShiftSpeed → COLLISION STRENGTH.
// The defaults are bumped so the lava looks ALIVE on open (heat non-zero). Wave R4
// replaces this with the proper six-knob set + its own typed properties. Keep these
// mirrored to the DEFAULT_* anchors in MixVisualizer.ts, as the existing sync discipline.
///
/// Default GRAVITY dial (R2 temp; was bulge). Mirrors DEFAULT_BUBBLYNESS in MixVisualizer.ts.
/// Normalized [0,1]; 0 = near-weightless float, 1 = wax falls + settles fast.
///
public const double DefaultBubblyness = 0.5;
///
/// Default HEAT dial (R2 temp; was detach). Mirrors DEFAULT_DETACH in MixVisualizer.ts.
/// Normalized [0,1]; 0 = wax rests at the bottom (collision-only), 1 = many bubbles rising.
/// Non-zero default so the lamp is alive on open.
///
public const double DefaultDetach = 0.45;
///
/// Default COLLISION-STRENGTH dial (R2 temp; was color-shift). Mirrors
/// DEFAULT_COLOR_SHIFT_SPEED in MixVisualizer.ts. Normalized [0,1]; 0 = soft shove,
/// 1 = hard elastic wall.
///
public const double DefaultColorShiftSpeed = 0.5;
/// Visible time-span in seconds (the resolution/zoom control). Reused as-is from 8.K.
public double VisibleSeconds { get; set; } = DefaultVisibleSeconds;
/// Bulge amount, normalized [0,1]. Inert until Wave 3 consumes the uniform.
public double Bubblyness { get; set; } = DefaultBubblyness;
/// Lava-lamp detachment, normalized [0,1]. Inert until Wave 3 consumes the uniform.
public double Detach { get; set; } = DefaultDetach;
/// Gradient-morph rate, normalized [0,1]. Inert until Wave 3 consumes the uniform.
public double ColorShiftSpeed { get; set; } = DefaultColorShiftSpeed;
///
/// Raised whenever any control value changes. The visualizer bridge subscribes to push the
/// affected uniform(s). Mutators set the property then raise this; subscribers re-read the values.
///
public event Action? Changed;
/// Raise . Called by the controls component after mutating a value.
public void NotifyChanged() => Changed?.Invoke();
}