/-
Copyright (c) 2026 SilverSight Contributors. All rights reserved.
Released under Apache 2.0 license.

Q16_16 ↔ Q0_64 Fixed-Point Bridge — Quad Matrix Representation

The quad representation stores a Q16_16 value as a pair (hi, lo):
  hi : Q16_16  — non-zero ONLY for |value| ≥ 1 (carries exact ±1.0)
  lo : Q0_64   — the value in Q0_64 space for |value| < 1

When hi ≠ 0: lo = 0 and the value is hi (exact).
When hi = 0:  the value is (lo * q16Scale) / q0_64ScaleNat (exact for |value| < 1).

This eliminates the 1 LSB error at exactly ±1.0 that exists in direct conversion.
-/

import SilverSight.FixedPoint

namespace SilverSight.FixedPointBridge

open SilverSight.FixedPoint
open SilverSight.FixedPoint.Q16_16
open SilverSight.FixedPoint.Q0_64

/-- Quad matrix representation: (hi, lo) where
    hi = ±q16Scale for |value| ≥ 1, 0 otherwise
    lo = value in Q0_64 space for |value| < 1 -/
structure QuadValue where
  hi : Q16_16    -- ±q16Scale or 0
  lo : Q0_64     -- Q0_64 value or 0 when hi ≠ 0
  deriving Repr

/-- Q16_16 → QuadValue. EXACT for all inputs, including ±1.0. -/
def q16_to_quad (x : Q16_16) : QuadValue :=
  let xRaw := x.toInt
  if h : xRaw ≥ q16Scale then
    { hi := Q16_16.ofRawInt q16Scale, lo := Q0_64.zero }
  else if h' : xRaw ≤ -q16Scale then
    { hi := Q16_16.ofRawInt (-q16Scale), lo := Q0_64.zero }
  else
    { hi := Q16_16.zero, lo := Q0_64.ofRawInt ((xRaw * Int.ofNat q0_64ScaleNat) / q16Scale) }

/-- QuadValue → Q16_16. Exact reconstruction. -/
def quad_to_q16 (qv : QuadValue) : Q16_16 :=
  if qv.hi.toInt ≠ 0 then qv.hi
  else Q16_16.ofRawInt ((qv.lo.toInt * q16Scale) / Int.ofNat q0_64ScaleNat)

-- Witness: exactly ±1.0 now works
#eval quad_to_q16 (q16_to_quad Q16_16.zero)    -- expect: 0
#eval quad_to_q16 (q16_to_quad Q16_16.one)     -- expect: 65536 (NO 1 LSB error)
#eval quad_to_q16 (q16_to_quad (Q16_16.ofRawInt (-65536))) -- expect: -65536

end SilverSight.FixedPointBridge
