{-# OPTIONS --safe #-}

module Data.Permutation.Normalised.Injective 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.Nat.Compare

step-lemma :  x y xs ys  (∀ n  xs ∘⟨ x , y   n  ys ∘⟨ x , y   n)   n  xs  n  ys  n
step-lemma x y xs ys p n with y  n 
... | no y≢n =
  let h =
        sym (cong  e  xs ⊙+ suc x  e) (swap-neq x (suc x + y) (suc x + n) (x≢sx+y x n) (y≢n  +-inj (suc x)))
        ; ⊙+⊙ (suc x) _ xs)
        ; sym (⊙-alg-com x y xs (suc x + n) ; cong′ {A = }  e  xs ⊙+ suc x  e) (⊙-· x y (suc (x + n))))
        ; p (suc x + n)
        ; ⊙-alg-com x y ys (suc x + n) ; cong′ {A = }  e  ys ⊙+ suc x  e) (⊙-· x y (suc (x + n)))
        ; cong  e  ys ⊙+ suc x  e) (swap-neq x (suc x + y) (suc x + n) (x≢sx+y x n) (y≢n  +-inj (suc x)))
        ; ⊙+⊙ (suc x) _ ys
  in +-inj (suc x) h
... | yes y≡n =
  let h = sym (⊙-alg-com x y xs x ; cong  e  xs ⊙+ suc x  e) (⊙-· x y x ; swap-lhs x _) ; ⊙+⊙ (suc x) y xs)
        ; p x
        ; ⊙-alg-com x y ys x ; cong  e  ys ⊙+ suc x  e) (⊙-· x y x ; swap-lhs x _) ; ⊙+⊙ (suc x) y ys
  in  cong (xs ⊙_) (sym y≡n) ; +-inj (suc x) h ; cong (ys ⊙_) y≡n

⊙-inj :  xs n m  xs  n  xs  m  n  m
⊙-inj xs n m p = perm-inj [ xs ]↑ n m (sym (⊙↑-hom xs n) ; p ; ⊙↑-hom xs m)

inj-⊙-lemma :  x xₜ yₜ xs ys
             (∀ n  xs ∘⟨ x , xₜ   n  ys ∘⟨ x , yₜ   n)
             xₜ  yₜ
             xs  xₜ  ys  yₜ
              n
             xs  n  ys  n
inj-⊙-lemma x xₜ yₜ xs ys p xₜ≢yₜ xye n with n  xₜ | n  yₜ
... | yes n≡xₜ | yes n≡yₜ = ⊥-elim (xₜ≢yₜ (sym n≡xₜ ; n≡yₜ))
... | no  n≢xₜ | yes n≡yₜ =
  ⊥-elim (x≢sx+y x (xs  n) (sym (sym (⊙-lhs x xₜ xs n (n≢xₜ  sym)) ; p (suc x + n) ; cong  e  ys ∘⟨ x , yₜ   suc x + e) n≡yₜ  ; ⊙-rhs x yₜ ys)))
... | yes n≡xₜ | no  n≢yₜ =
  ⊥-elim (x≢sx+y x (ys  n)
    ( sym (⊙-rhs x xₜ xs)
    ; cong  e  xs ∘⟨ x , xₜ   suc x + e) (sym n≡xₜ)
    ; p (suc x + n)
    ; ⊙-lhs x yₜ ys n (n≢yₜ  sym)
    ))
... | no  n≢xₜ | no  n≢yₜ =
  +-inj (suc x) (sym (⊙-lhs x xₜ xs n (n≢xₜ  sym)) ; p (suc x + n) ; ⊙-lhs x yₜ ys n (n≢yₜ  sym))

inj-⊙ :  xs ys  (∀ n  xs  n  ys  n)  xs  ys
inj-⊙ ⟨⟩ ⟨⟩ _ = refl
inj-⊙ ⟨⟩ (ys ∘⟨ x , y ) p = ⊥-elim (⊙-lhs-neq x y ys (sym (p x)))
inj-⊙ (xs ∘⟨ x , y ) ⟨⟩ p = ⊥-elim (⊙-lhs-neq x y xs (p x))
inj-⊙ (xs ∘⟨ xₛ , xₜ ) (ys ∘⟨ yₛ , yₜ ) p with xₛ  yₛ | xₜ  yₜ

... | yes xₛ≡yₛ | yes xₜ≡yₜ = cong₂ _∘⟨_⟩ (inj-⊙ xs ys  λ n  step-lemma xₛ xₜ xs ys ( cong₂  e₁ e₂  ys ∘⟨ e₁ , e₂   _) (sym xₛ≡yₛ) (sym xₜ≡yₜ)  p) n ) (cong₂ _,_ xₛ≡yₛ xₜ≡yₜ)
... | yes xₛ≡yₛ | no xₜ≢yₜ =
  let h = +-inj (suc xₛ) $ sym (⊙-alg-com xₛ xₜ xs xₛ ; cong  e  xs ⊙+ suc xₛ  e) (⊙-· xₛ xₜ xₛ ; swap-lhs xₛ _) ; ⊙+⊙ (suc xₛ) xₜ xs)
        ; p xₛ
        ; cong (ys ∘⟨ yₛ , yₜ  ⊙_) xₛ≡yₛ
        ; ⊙-alg-com yₛ yₜ ys yₛ ; cong  e  ys ⊙+ suc yₛ  e) (⊙-· yₛ yₜ yₛ ; swap-lhs yₛ _) ; ⊙+⊙ (suc yₛ) yₜ ys
        ; cong suc (cong (_+ (ys  yₜ)) (sym xₛ≡yₛ)) 
      h′ = inj-⊙ xs ys (inj-⊙-lemma xₛ xₜ yₜ xs ys ( λ n  p n ; cong  e  ys ∘⟨ e , yₜ   n) (sym xₛ≡yₛ) ) xₜ≢yₜ h )
          
      h″ = ⊙-inj xs xₜ yₜ (h ; cong (_⊙ yₜ) (sym h′))
  in ⊥-elim (xₜ≢yₜ h″)
... | no  xₛ≢yₛ | _ with compare xₛ yₛ | comparing xₛ yₛ
... | equal | xₛ≡yₛ = ⊥-elim (xₛ≢yₛ xₛ≡yₛ)
... | less    k | xₛ<yₛ =
  ⊥-elim (⊙-lhs-neq xₛ xₜ xs (p xₛ ; cong  e  ys ∘⟨ e , yₜ   xₛ) (sym xₛ<yₛ) ; ⊙-lt (ys ∘⟨ k , yₜ ) xₛ))
... | greater k | yₛ<xₛ =
  ⊥-elim (⊙-lhs-neq yₛ yₜ ys (sym (p yₛ) ; cong  e  xs ∘⟨ e , xₜ   yₛ) (sym yₛ<xₛ) ; ⊙-lt (xs ∘⟨ k , xₜ ) yₛ))