{-# OPTIONS --cubical #-}

module Data.Binary.Properties.Conversion where

open import Data.Binary.Conversion
open import Data.Binary.Definition
open import Data.Binary.Increment
import Data.Binary.Conversion.Fast as F
open import Data.Binary.Conversion.Fast using (⟦_⇑⟧⟨_⟩)

open import Data.Binary.Helpers
open import Data.Binary.Properties.Helpers
import Agda.Builtin.Nat as 
open import Agda.Builtin.Bool

tail𝔹 : 𝔹  𝔹
tail𝔹 0ᵇ = 0ᵇ
tail𝔹 (1ᵇ xs) = xs
tail𝔹 (2ᵇ xs) = xs

tail𝔹-inc :  xs  inc (tail𝔹 (inc xs))  tail𝔹 (inc (inc (inc xs)))
tail𝔹-inc 0ᵇ = refl
tail𝔹-inc (1ᵇ xs) = refl
tail𝔹-inc (2ᵇ xs) = refl

tail-homo :  n  tail𝔹 (inc  n ⇑⟧)   div2 n ⇑⟧
tail-homo n = go n  cong ⟦_⇑⟧ (sym (div-helper-lemma 0 1 n 1))
  where
  go :  n  tail𝔹 (inc  n ⇑⟧)   div-helper′ 1 n 1 ⇑⟧
  go zero = refl
  go (suc zero) = refl
  go (suc (suc n)) = sym (tail𝔹-inc  n ⇑⟧)  cong inc (go n)

head𝔹 : 𝔹  Maybe Bool
head𝔹 0ᵇ = nothing
head𝔹 (1ᵇ xs) = just true
head𝔹 (2ᵇ xs) = just false

head𝔹-inc :  xs  head𝔹 (inc (inc (inc xs)))  head𝔹 (inc xs)
head𝔹-inc 0ᵇ = refl
head𝔹-inc (1ᵇ xs) = refl
head𝔹-inc (2ᵇ xs) = refl

head𝔹-homo :  n  head𝔹 (inc  n ⇑⟧)  just (even n)
head𝔹-homo zero    = refl
head𝔹-homo (suc zero) = refl
head𝔹-homo (suc (suc n)) = head𝔹-inc  n ⇑⟧  head𝔹-homo n

head-tail-cong :  xs ys  head𝔹 xs  head𝔹 ys  tail𝔹 xs  tail𝔹 ys  xs  ys
head-tail-cong 0ᵇ 0ᵇ h≡ t≡ = refl
head-tail-cong 0ᵇ (1ᵇ ys) h≡ t≡ = ⊥-elim (¬nothing≡just h≡)
head-tail-cong 0ᵇ (2ᵇ ys) h≡ t≡ = ⊥-elim (¬nothing≡just h≡)
head-tail-cong (1ᵇ xs) 0ᵇ h≡ t≡ = ⊥-elim (¬just≡nothing h≡)
head-tail-cong (1ᵇ xs) (1ᵇ ys) h≡ t≡ = cong 1ᵇ_ t≡
head-tail-cong (1ᵇ xs) (2ᵇ ys) h≡ t≡ = ⊥-elim (subst (bool  ) (just-inj h≡) tt)
head-tail-cong (2ᵇ xs) 0ᵇ h≡ t≡ = ⊥-elim (¬just≡nothing h≡)
head-tail-cong (2ᵇ xs) (1ᵇ ys) h≡ t≡ = ⊥-elim (subst (bool  ) (just-inj h≡) tt)
head-tail-cong (2ᵇ xs) (2ᵇ ys) h≡ t≡ = cong 2ᵇ_ t≡

div2≤ :  n m  n  m  div2 n  m
div2≤ n m = ≤-trans (div2 n) n m (div2-≤ n)

fast-correct-helper :  n w  n  w   n ⇑⟧⟨ w    n ⇑⟧
fast-correct-helper zero    w       p = refl
fast-correct-helper (suc n) (suc w) p =
    head-tail-cong _ (inc  n ⇑⟧)
      (lemma₁ (even n)  div2 n ⇑⟧⟨ w   sym (head𝔹-homo n))
      (lemma₂ (even n)  div2 n ⇑⟧⟨ w   fast-correct-helper (div2 n) w (div2≤ n w (p≤p n w p))  sym (tail-homo n))
  where
  lemma₁ :  x xs  head𝔹 (if x then 1ᵇ xs else 2ᵇ xs)  just x
  lemma₁ false xs = refl
  lemma₁ true  xs = refl

  lemma₂ :  x xs  tail𝔹 (if x then 1ᵇ xs else 2ᵇ xs)  xs
  lemma₂ false xs = refl
  lemma₂ true xs  = refl

fast-correct :  n  F.⟦ n ⇑⟧   n ⇑⟧
fast-correct n = fast-correct-helper n n (≤-refl n)