{-# OPTIONS --cubical --safe #-}

module Data.Rational.SternBrocot where

open import Prelude
import Data.Nat as 
import Data.Nat.Properties as 
open import Data.Bits renaming (Bits to ℚ⁺; [] to 1ℚ; 0∷_ to lℚ; 1∷_ to rℚ)
open import Data.Bits.Equatable

-- ⟦_⇓⟧ : ℚ⁺ → (ℕ × ℕ)
-- ⟦ 1ℚ ⇓⟧ = 1 , 1
-- ⟦ lℚ x ⇓⟧ = let p , q = ⟦ x ⇓⟧ in p , p ℕ.+ q
-- ⟦ rℚ x ⇓⟧ = let p , q = ⟦ x ⇓⟧ in p ℕ.+ q , q

-- module TerminationProofs where
--   Tᴮ⇒≡ : {n m : ℕ} → n ≡ m → T (n ℕ.≡ᴮ m)
--   Tᴮ⇒≡ {n} {m} n≡m = subst (λ n′ → T (n ℕ.≡ᴮ n′)) n≡m (ℕ.complete-== n)

--   lift-suc-≡ : ∀ {n m} s → m ≡ n → T (n ℕ.≡ᴮ s) → T (m ℕ.≡ᴮ s)
--   lift-suc-≡ {n} {m} s  m≡n p = Tᴮ⇒≡ (m≡n ; ℕ.sound-== (n) s p)

--   lemma₁ : ∀ a m → a ℕ.+ m ℕ.+ zero ≡ m ℕ.+ a
--   lemma₁ a m = ℕ.+-idʳ (a ℕ.+ m) ; ℕ.+-comm a m

--   lemma₂ : ∀ n a m → n ℕ.+ m ℕ.+ suc a ≡ n ℕ.+ suc m ℕ.+ a
--   lemma₂ n a m = ℕ.+-assoc n m (suc a) ; cong (n ℕ.+_) (ℕ.+-suc m a) ; sym (ℕ.+-assoc n (suc m) a)

--   lemma₃ : ∀ n a → n ℕ.+ a ℕ.+ zero ≡ n ℕ.+ zero ℕ.+ a
--   lemma₃ n a = ℕ.+-idʳ (n ℕ.+ a) ; cong (ℕ._+ a) (sym (ℕ.+-idʳ n))

-- _+1/_+1 : ℕ → ℕ → ℚ⁺
-- n +1/ m +1 = go zero n m (n ℕ.+ m)
--   where
--   go : (a n m s : ℕ) → ℚ⁺
--   go a zero    (suc m) (suc s) = lℚ (go zero a m s)
--   go a (suc n) (suc m) (suc s) = go (suc a) n m s
--   go a (suc n) zero    (suc s) = rℚ (go zero n a s)
--   go _ _       _       _       = 1ℚ

euclidian :       ℚ⁺
euclidian n m zero    = 1ℚ
euclidian n m (suc s) =
  if n ℕ.Eqℕ.≡ᴮ m
  then 1ℚ
  else if n ℕ.<ᴮ m
  then lℚ (euclidian n (m ℕ.∸ (1 ℕ.+ n)) s)
  else rℚ (euclidian (n ℕ.∸ (1 ℕ.+ m)) m s)

normalise-suc :     ℚ⁺
normalise-suc n m = euclidian n m (n ℕ.+ m)

 : Type
 = ℚ⁺

import Data.Rational.Unnormalised as F
open import Data.Rational.Unnormalised using (_/suc_; _/_)
import Data.Integer as 
open import Data.Integer using (; ; ⁻suc; )
open import Data.Bits.Fold

zer : ( × )  ( × )
zer (p , q) = p , suc p ℕ.+ q

one : ( × )  ( × )
one (p , q) = suc p ℕ.+ q , q

fraction :   ( × )
fraction = foldr-bits zer one (0 , 0)

⟦_⇓⟧ :   F.ℚ
 1ℚ ⇓⟧ =  0 F./suc 0
 lℚ xs ⇓⟧ = let n , d = fraction xs in ⁻suc n /suc d
 rℚ xs ⇓⟧ = let n , d = fraction xs in  (suc n) /suc d

⟦_⇑⟧ : F.ℚ  
  zero /suc den-pred ⇑⟧ = 1ℚ
  (suc x) /suc den-pred ⇑⟧ = rℚ (normalise-suc x den-pred)
 ⁻suc x /suc den-pred ⇑⟧ = lℚ (normalise-suc x den-pred)

-- open import Path.Reasoning

-- n≢sn+d : ∀ n d → (n ℕ.≡ᴮ suc (n ℕ.+ d)) ≡ false
-- n≢sn+d zero d = refl
-- n≢sn+d (suc n) d = n≢sn+d n d

-- n<sn+d : ∀ n d → (n ℕ.<ᴮ suc (n ℕ.+ d)) ≡ true
-- n<sn+d zero d = refl
-- n<sn+d (suc n) d = n<sn+d n d

-- n+d-n≡d : ∀ n d → n ℕ.+ d ℕ.∸ n ≡ d
-- n+d-n≡d zero d = refl
-- n+d-n≡d (suc n) d = n+d-n≡d n d

-- euclidian-term-helper : ∀ n d s₁ s₂ → (n ℕ.+ d ℕ.≤ s₁) → (n ℕ.+ d ℕ.≤ s₂) → euclidian n d s₁ ≡ euclidian n d s₂
-- euclidian-term-helper zero zero zero zero p₁ p₂ = refl
-- euclidian-term-helper zero zero zero (suc s₂) p₁ p₂ = refl
-- euclidian-term-helper zero zero (suc s₁) zero p₁ p₂ = refl
-- euclidian-term-helper zero zero (suc s₁) (suc s₂) p₁ p₂ = refl
-- euclidian-term-helper zero (suc d) (suc s₁) (suc s₂) p₁ p₂ = cong lℚ (euclidian-term-helper zero d s₁ s₂ (ℕ.p≤p d s₁ p₁) (ℕ.p≤p d s₂ p₂))
-- euclidian-term-helper (suc n) zero (suc s₁) (suc s₂) p₁ p₂ = cong rℚ (euclidian-term-helper n zero s₁ s₂ (ℕ.p≤p (n ℕ.+ zero) s₁ p₁) (ℕ.p≤p (n ℕ.+ zero) s₂ p₂))
-- euclidian-term-helper (suc n) (suc d) (suc s₁) (suc s₂) p₁ p₂ with n ℕ.≡ᴮ d | n ℕ.<ᴮ d
-- euclidian-term-helper (suc n) (suc d) (suc s₁) (suc s₂) p₁ p₂ | false | false = cong rℚ (euclidian-term-helper (n ℕ.∸ suc d) (suc d) s₁ s₂ {!!} {!!})
-- euclidian-term-helper (suc n) (suc d) (suc s₁) (suc s₂) p₁ p₂ | false | true  = cong lℚ (euclidian-term-helper (suc n) (d ℕ.∸ suc n) s₁ s₂ {!!} {!!})
-- euclidian-term-helper (suc n) (suc d) (suc s₁) (suc s₂) p₁ p₂ | true  | _ = refl

-- norm-l : ∀ n d → normalise-suc n (suc n ℕ.+ d) ≡ lℚ (normalise-suc n d)
-- norm-l n d =
--   normalise-suc n (suc n ℕ.+ d) ≡⟨⟩
--   euclidian n (suc n ℕ.+ d) (n ℕ.+ (suc n ℕ.+ d)) ≡⟨ cong (euclidian n (suc n ℕ.+ d)) (ℕ.+-suc n (n ℕ.+ d)) ⟩
--   euclidian n (suc n ℕ.+ d) (suc n ℕ.+ (n ℕ.+ d)) ≡⟨⟩
--   (if n ℕ.≡ᴮ suc (n ℕ.+ d) then 1ℚ else
--        if n ℕ.<ᴮ suc (n ℕ.+ d) then lℚ (euclidian n (n ℕ.+ d ℕ.∸ n) (n ℕ.+ (n ℕ.+ d))) else rℚ (euclidian (n ℕ.∸ suc (suc (n ℕ.+ d))) (suc (n ℕ.+ d)) (n ℕ.+ (n ℕ.+ d)))) ≡⟨ cong (if_then 1ℚ else if n ℕ.<ᴮ suc (n ℕ.+ d) then lℚ (euclidian n (n ℕ.+ d ℕ.∸ n) (n ℕ.+ (n ℕ.+ d))) else rℚ (euclidian (n ℕ.∸ suc (suc (n ℕ.+ d))) (suc (n ℕ.+ d)) (n ℕ.+ (n ℕ.+ d)))) (n≢sn+d n d) ⟩
--   (if n ℕ.<ᴮ suc (n ℕ.+ d) then
--        lℚ (euclidian n (n ℕ.+ d ℕ.∸ n) (n ℕ.+ (n ℕ.+ d))) else
--        rℚ (euclidian (n ℕ.∸ suc (suc (n ℕ.+ d))) (suc (n ℕ.+ d)) (n ℕ.+ (n ℕ.+ d)))) ≡⟨ cong (if_then lℚ ((euclidian n (n ℕ.+ d ℕ.∸ n) (n ℕ.+ (n ℕ.+ d)))) else rℚ ((euclidian (n ℕ.∸ suc (suc (n ℕ.+ d))) (suc (n ℕ.+ d)) (n ℕ.+ (n ℕ.+ d))))) (n<sn+d n d) ⟩
--   lℚ (euclidian n (n ℕ.+ d ℕ.∸ n) (n ℕ.+ (n ℕ.+ d))) ≡⟨ cong (λ ndn → lℚ (euclidian n ndn (n ℕ.+ (n ℕ.+ d)))) (n+d-n≡d n d) ⟩
--   lℚ (euclidian n d (n ℕ.+ (n ℕ.+ d))) ≡⟨ {!!} ⟩
--   lℚ (euclidian n d (n ℕ.+ d)) ≡⟨⟩
--   lℚ (normalise-suc n d) ∎


-- ℚ-retract′ : ∀ x → normalise-suc (fst (fraction x)) (snd (fraction x)) ≡ x
-- ℚ-retract′ 1ℚ = refl
-- ℚ-retract′ (rℚ x) = {!!}
-- ℚ-retract′ (lℚ x) = let n , d = fraction x in
--   normalise-suc n (suc (n ℕ.+ d)) ≡⟨ {!!} ⟩
--   lℚ x ∎

-- ℚ-retract : ∀ x → ⟦ ⟦ x ⇓⟧ ⇑⟧ ≡ x
-- ℚ-retract 1ℚ = refl
-- ℚ-retract (lℚ x) = cong lℚ (ℚ-retract′ x)
-- ℚ-retract (rℚ x) = cong rℚ (ℚ-retract′ x)