{-# OPTIONS --safe #-}

module Data.Permutation.Normalised.RoundTrip where

open import Prelude hiding (_↔_)
open import Data.List hiding ([]; _∷_)
open import Data.Nat.Properties renaming (discreteℕ to infix 4 _≟_)
open import Data.Permutation.Swap _≟_
open import Data.Permutation.NonNorm _≟_
open import Data.Nat using (_+_)
open import Data.Permutation.Normalised.Definition
open import Data.List.Properties
open import Data.Permutation.Normalised.Unnorm
open import Data.Permutation.Normalised.Norm
open import Data.Nat.Compare
open import Path.Reasoning
open import Data.Maybe

unf-coalg :     (  Diffs)    Diffs
unf-coalg x y k n = k (suc n + x) ∘⟨ n + x , y  

un-diff : Diffs    Diffs
un-diff = foldr (uncurry unf-coalg) (const ⟨⟩)

compare-diff-+ :  x y  compare x (suc x + y)  less y
compare-diff-+ zero y = refl
compare-diff-+ (suc x) y = compare-diff-+ x y

norm-lemma₁ :  xs x y  xs ⊙+ suc x ⊙⟨ x , y   xs ∘⟨ x , y 
norm-lemma₁ ⟨⟩ x y = refl
norm-lemma₁ (xs ∘⟨ s , t ) x y with compare x (suc x + s) | comparing x (suc x + s)
... | less    k | sx+k≡sx+s = cong  e  xs ∘⟨ e , t  ∘⟨ x , y ) (+-inj (suc x) sx+k≡sx+s)
... | equal     | x≡sx+s = ⊥-elim (x≢sx+y x s x≡sx+s)
... | greater k | p = ⊥-elim (x≢sx+y x (suc s + k) (sym p ; cong suc (cong suc (+-assoc x s k) ; sym (+-suc x (s + k)))))

norm-lemma :  xs n  foldr (flip _⊙⟨_⟩) ⟨⟩ (un-diff xs n)  xs ⊙+ n
norm-lemma ⟨⟩ n = refl
norm-lemma (xs ∘⟨ x , y ) n =
  foldr (flip _⊙⟨_⟩) ⟨⟩ (un-diff (xs ∘⟨ x , y ) n) ≡⟨⟩
  foldr (flip _⊙⟨_⟩) ⟨⟩ (un-diff xs (suc n + x) ∘⟨ n + x , y ) ≡⟨⟩
  foldr (flip _⊙⟨_⟩) ⟨⟩ (un-diff xs (suc n + x)) ⊙⟨ n + x , y  ≡⟨ cong (_⊙⟨ n + x , y ) (norm-lemma xs (suc n + x)) 
  xs ⊙+ suc n + x ⊙⟨ n + x , y  ≡⟨ norm-lemma₁ xs (n + x) y 
  xs ∘⟨ n + x , y  

norm-inv :  xs  [ [ xs ]↑ ]↓  xs
norm-inv xs =
  [ [ xs ]↑ ]↓ ≡⟨⟩
  [ foldr (uncurry unflatten-alg) (const ⟨⟩) xs 0 ]↓ ≡⟨⟩
  foldr (flip _⊙⟨_⟩) ⟨⟩ (catMaybes (uncurry swap-diff) (foldr (uncurry unflatten-alg) (const ⟨⟩) xs 0))
    ≡⟨ cong′ {A =   Swaps}  k  foldr (flip _⊙⟨_⟩) ⟨⟩ (k 0)) (foldr-fusion  xs n  catMaybes (uncurry swap-diff) (xs n)) (const ⟨⟩)  { (x , y) k  funExt λ n  cong (maybe _ _) (cong (mapMaybe (map₁ (bool′ (n + x) _))) (compare-diff-+ (n + x) y)) }) xs) 
  foldr (flip _⊙⟨_⟩) ⟨⟩ (un-diff xs 0)
    ≡⟨  norm-lemma xs 0 
  xs ⊙+ 0
    ≡⟨ shift-0 xs 
  xs