{-# OPTIONS --without-K --rewriting #-}

module Pi.Coxeter.LehmerCoxeterEquiv where

open import lib.Base
open import lib.NType
open import lib.NType2
open import lib.Equivalence
open import lib.PathGroupoid
open import lib.types.Fin
open import lib.types.List
open import lib.types.LoopSpace

open import Pi.Coxeter.LehmerImmersion renaming (immersion to immersionLehmer)
open import Pi.Common.ListFinLListEquiv
open import Pi.Common.LList
open import Pi.Common.ListN
open import Pi.Coxeter.NonParametrized.ReductionRel
open import Pi.Coxeter.NonParametrized.MCoxeter
open import Pi.Coxeter.NonParametrized.LehmerCanonical using (only-one-canonical↔)
open import Pi.Coxeter.NonParametrized.LehmerReduction using (Listℕ-to-Lehmer)
open import Pi.Coxeter.Parametrized.ReductionRel
open import Pi.Coxeter.Parametrized.CoxeterMCoxeterEquiv
open import Pi.Coxeter.Parametrized.MCoxeter
open import Pi.Coxeter.Coxeter
open import Pi.Common.Extra
open import Pi.Common.Misc
open import Pi.UFin.UFin

immersion : {n : } -> Lehmer n -> List (Fin n)
immersion {O} CanZ = nil
immersion {S n} code = <– List≃LList (immersionLehmer code , immersion->> code)

ListFin-to-Lehmer : {n : } -> (m : List (Fin (S n))) -> Σ (Lehmer (S n))  cl -> m ≈* immersion cl)
ListFin-to-Lehmer {n} m =
    let r , rp = –> List≃LList (reverse m)
        np , cl , cl-p = Listℕ-to-Lehmer r
        n>>cl = reduction-implies->> (LList-rev (r , rp)) (immersionLehmer cl) cl-p
        cln , cln-p = >>-drop cl (S n) n>>cl
        n>>cln = transport  e -> S n >> e) (! cln-p) n>>cl
        cln-f = ((immersionLehmer cln) , n>>cln)

        lemma : rev r ≅* immersionLehmer cln
        lemma = transport  e -> (rev r) ≅* e) (! cln-p) cl-p

        reduction : <– List≃LList (LList-rev (r , rp)) ≅*[ n ] <– List≃LList cln-f
        reduction = reduction-fromLList* (LList-rev (r , rp)) cln-f lemma

        reduction-t : m ≅*[ n ] <– List≃LList cln-f
        reduction-t = transport  e -> e ≅*[ n ] (<– List≃LList cln-f)) (ap fromLList (rev-reverse m)  fromLList∘toLList m) reduction

        idp-t : immersion cln ≅*[ n ] (<– List≃LList cln-f)
        idp-t = transport  e -> e ≅*[ n ] (<– List≃LList cln-f)) (ap fromLList (LList-eq idp)) idpN
    in  cln , mcoxeter->coxeter _ _ (MC reduction-t idp-t)

immersion-is-injection : {n : } -> (cl1 cl2 : Lehmer (S n)) -> ((immersion cl1) ≈* (immersion cl2)) -> cl1 == cl2
immersion-is-injection cl1 cl2 p with coxeter->mcoxeter p
... | (MC {_} {_} {lf} p1 p2) =
    let c1 = reduction-toLList* _ _ p1
        c2 = reduction-toLList* _ _ p2
        c1t = transport  e -> e ≅* _) (ap fst (toLList∘fromLList _)) c1
        c2t = transport  e -> e ≅* _) (ap fst (toLList∘fromLList _)) c2
    in  only-one-canonical↔ cl1 cl2 _ _ idp idp (MC c1t c2t)

immersion⁻¹ : {n : } ->  List (Fin n)  Lehmer n
immersion⁻¹ {O} nil = CanZ
immersion⁻¹ {S n} m = ListFin-to-Lehmer m .fst

immersion⁻¹-respects≈ :  {n : } ->  {m1 m2 : List (Fin n)}  m1 ≈* m2  immersion⁻¹ m1 == immersion⁻¹ m2
immersion⁻¹-respects≈ {O} {nil} {nil} pm = idp
immersion⁻¹-respects≈ {S n} {m1} {m2} pm =
    let (cl1 , cl1p) = ListFin-to-Lehmer m1
        (cl2 , cl2p) = ListFin-to-Lehmer m2
        p = (comm {S n} cl1p)  pm  cl2p
    in immersion-is-injection cl1 cl2 p

immersion∘immersion⁻¹ : {n : } -> (m : List (Fin n))  immersion (immersion⁻¹ m) ≈* m
immersion∘immersion⁻¹ {O} nil = idp
immersion∘immersion⁻¹ {S n} m = comm {S n} (ListFin-to-Lehmer m .snd)

immersion⁻¹∘immersion : {n : } ->  (cl : Lehmer n)  immersion⁻¹ (immersion cl) == cl
immersion⁻¹∘immersion {O} CanZ = idp
immersion⁻¹∘immersion {S n} cl =
    let cln , cln-p = ListFin-to-Lehmer (<– List≃LList (immersionLehmer cl , immersion->> cl))
    in  immersion-is-injection cln cl (comm cln-p)