import Semantics.FixedPoint

/-!
# FixedPointBoundary — Float ↔ Q16_16 / Q0_16 / Q0_64 conversion

These functions are **only** for the I/O boundary: parsing JSON, reading sensor
data, or displaying values in `#eval` witnesses. They must NOT be used in any
compute-path definition that feeds into a receipt, score, or gate.

The core `Semantics.FixedPoint` module is Float-free by design.
-/

namespace Semantics.FixedPoint

-- ═══════════════════════════════════════════════════════════════════════════
-- Q0.16 Float boundary
-- ═══════════════════════════════════════════════════════════════════════════

namespace Q0_16

def toFloat (q : Q0_16) : Float :=
  Float.ofInt q.toInt / 32767.0

def ofFloat (f : Float) : Q0_16 :=
  if f.isNaN then zero
  else if f ≥ 1.0 then one
  else if f ≤ -1.0 then neg one
  else if f < 0.0 then
    ofRawInt (-(Int.ofNat ((-f * 32767.0).round.toUInt16.toNat)))
  else
    ofRawInt (Int.ofNat ((f * 32767.0).round.toUInt16.toNat))

end Q0_16

-- ═══════════════════════════════════════════════════════════════════════════
-- Q16.16 Float boundary
-- ═══════════════════════════════════════════════════════════════════════════

namespace Q16_16

@[inline]
def ofFloat (f : Float) : Q16_16 :=
  if f.isNaN || f ≥ 32768.0 then infinity
  else if f ≤ -32768.0 then minVal
  else if f < 0.0 then
    ofRawInt (-(Int.ofNat ((-f * 65536.0).floor.toUInt32.toNat)))
  else
    ofRawInt (Int.ofNat ((f * 65536.0).floor.toUInt32.toNat))

@[inline]
def toFloat (q : Q16_16) : Float :=
  Float.ofInt q.toInt / 65536.0

end Q16_16

-- ═══════════════════════════════════════════════════════════════════════════
-- Q0.64 Float boundary
-- ═══════════════════════════════════════════════════════════════════════════

def q0_64ScaleFloat : Float := 9223372036854775808.0

namespace Q0_64

def ofFloat (f : Float) : Q0_64 :=
  if f.isNaN || f ≥ 1.0 then one
  else if f ≤ -1.0 then ofRawInt q0_64MinRaw
  else if f < 0.0 then
    ofRawInt (-(Int.ofNat ((-f * q0_64ScaleFloat).floor.toUInt64.toNat)))
  else
    ofRawInt (Int.ofNat ((f * q0_64ScaleFloat).floor.toUInt64.toNat))

def toFloat (q : Q0_64) : Float :=
  Float.ofInt q.toInt / q0_64ScaleFloat

end Q0_64

end Semantics.FixedPoint

namespace Semantics
  namespace Q16_16
    export FixedPoint.Q16_16 (ofFloat toFloat)
  end Q16_16
  namespace Q0_16
    export FixedPoint.Q0_16 (toFloat ofFloat)
  end Q0_16
  namespace Q0_64
    export FixedPoint.Q0_64 (ofFloat toFloat)
  end Q0_64
end Semantics
