{-# OPTIONS --safe #-}

open import Definition.Typed.EqualityRelation

module Definition.LogicalRelation.Properties.Universe {{eqrel : EqRelSet}} where
open EqRelSet {{...}}

open import Definition.Untyped
open import Definition.Untyped.Properties
open import Definition.Typed
open import Definition.Typed.Weakening
open import Definition.LogicalRelation
open import Definition.LogicalRelation.Weakening as Lwk
open import Definition.LogicalRelation.ShapeView
open import Definition.LogicalRelation.Irrelevance as Irr
open import Definition.Typed.Properties
open import Definition.LogicalRelation.Properties.MaybeEmb
open import Definition.LogicalRelation.Properties.Escape
open import Definition.LogicalRelation.Properties.Reduction
open import Definition.LogicalRelation.Properties.Conversion
open import Tools.Product
import Tools.PropositionalEquality as PE
open import Tools.Empty using (⊥; ⊥-elim)

import Data.Fin as Fin
import Data.Nat as Nat

Ugen : ∀ {Γ rU l} → (⊢Γ : ⊢ Γ) →  Γ ⊩⟨ next l ⟩ Univ rU l ^ [ ! , next l ]
Ugen {Γ} {rU} {⁰} ⊢Γ = Uᵣ′ (Univ rU ⁰) (ι ¹) rU ⁰ emb< PE.refl ((idRed:*: (Ugenⱼ ⊢Γ)))
Ugen {Γ} {rU} {¹} ⊢Γ = Uᵣ′ (Univ rU ¹) ∞ rU ¹ ∞< PE.refl (idRed:*: (Uⱼ ⊢Γ))

U-Relevance-Level : ∀ {l ll Γ A} ([U] : Γ ⊩⟨ l ⟩U A ^ ll) → Relevance × Level
U-Relevance-Level (noemb (Uᵣ r l′ l< eq d)) =  r , l′
U-Relevance-Level (emb x X) = U-Relevance-Level X

univRedTerm : ∀ {Γ r l u t ti}
        → Γ ⊢ Univ r l ⇒ u ∷ t ^ ti
        → ⊥
univRedTerm (conv d′ A≡t) = univRedTerm d′

univRed* : ∀ {Γ r l r′ l′ ti}
         → Γ ⊢ Univ r l ⇒* Univ r′ l′ ^ ti
         → (r PE.≡ r′) × (l PE.≡ l′)
univRed* (id x) = PE.refl , PE.refl
univRed* (univ x ⇨ D) = ⊥-elim (univRedTerm x)

-- Reducible terms of type U are reducible types.
univEq : ∀ {l Γ A r l′ ll′}
       → ([U] : Γ ⊩⟨ l ⟩ Univ r l′ ^ [ ! , ll′ ] )
       → Γ ⊩⟨ l ⟩ A ∷ Univ r l′ ^ [ ! , ll′ ] / [U]
       → Γ ⊩⟨ ι l′ ⟩ A ^ [ r , ι l′ ]
univEq {ι ⁰} {Γ} {A} {r} {l′} (Uᵣ (Uᵣ r₁ l′₁ () eq [[ ⊢A , ⊢B , D ]])) (Uₜ K d₁ typeK K≡K [t])
univEq {ι ¹} {Γ} {A} {r} {l′} (Uᵣ (Uᵣ r₁ ⁰ emb< eq [[ ⊢A , ⊢B , D ]])) (Uₜ K d₁ typeK K≡K [t]) =
  let
    ⊢Γ = wf ⊢A
    r≡r₁ , l′≡l′₁ = univRed* D
    [t]′ : Γ ⊩⟨ ι ⁰ ⟩ A ^ [ r₁ , ι ⁰ ]
    [t]′ = PE.subst (λ X → Γ ⊩⟨ _ ⟩ X ^ [ _ , _ ])
      (Definition.Untyped.Properties.wk-id A) ([t] Definition.Typed.Weakening.id ⊢Γ)
  in
  PE.subst₂ (λ X Y → Γ ⊩⟨ ι Y ⟩ A ^ [ X , ι Y ]) (PE.sym r≡r₁) (PE.sym l′≡l′₁) [t]′
univEq {∞} {Γ} {A} {r} {l′} (Uᵣ (Uᵣ r₁ ¹ _ eq [[ ⊢A , ⊢B , D ]])) (Uₜ K d₁ typeK K≡K [t]) =
  let
    ⊢Γ = wf ⊢A
    r≡r₁ , l′≡l′₁ = univRed* D
    [t]′ : Γ ⊩⟨ ι ¹ ⟩ A ^ [ r₁ , ι ¹ ]
    [t]′ = PE.subst (λ X → Γ ⊩⟨ _ ⟩ X ^ [ _ , _ ])
      (Definition.Untyped.Properties.wk-id A) ([t] Definition.Typed.Weakening.id ⊢Γ)
  in
  PE.subst₂ (λ X Y → Γ ⊩⟨ ι Y ⟩ A ^ [ X , ι Y ]) (PE.sym r≡r₁) (PE.sym l′≡l′₁) [t]′
univEq (ℕᵣ [[ ⊢A , ⊢B , univ x ⇨ D ]]) [A] = ⊥-elim (univRedTerm x)
univEq (ne′ K [[ ⊢A , ⊢B , univ x ⇨ D ]] neK K≡K) [A] = ⊥-elim (univRedTerm x)
univEq (Πᵣ′ rF lF lG _ _ F G [[ ⊢A , ⊢B , univ x ⇨ D ]] ⊢F ⊢G A≡A [F] [G] G-ext) [A] =
  ⊥-elim (univRedTerm x)
univEq {ι ¹} (emb _ [U]′) [A] = univEq [U]′ [A]
univEq {∞} (emb _ [U]′) [A] = univEq [U]′ [A]

univEqGen : ∀ {Γ UA A l′}
       → ([U] : ((next l′) LogRel.⊩¹U logRelRec (next l′) ^ Γ) UA (next l′))
       → Γ ⊩⟨ next l′ ⟩ A ∷ UA ^ [ ! , next l′ ] / Uᵣ [U]
       → Γ ⊩⟨ ι l′ ⟩ A ^ [ LogRel._⊩¹U_^_.r [U] , ι l′ ]
univEqGen {Γ} {UA} {A} {l′} [UA] [A] =
  let (Uᵣ r l′₁ l< e [[ ⊢A , ⊢B , D ]]) = [UA]
      [U] = Ugen {l = l′} (wf ⊢A)
      [UA]' , [UAeq] = redSubst* (PE.subst (λ X →  Γ ⊢ UA ⇒* Univ r X ^ [ ! , next X ]) (next-inj e) D) [U]
  in univEq [U] (convTerm₁ {t = A} [UA]' [U] [UAeq] (irrelevanceTerm (Uᵣ [UA]) [UA]' [A]))

univ⊩ : ∀ {A Γ rU lU lU' l}
        ([U] : Γ ⊩⟨ l ⟩ Univ rU lU ^ [ ! , lU' ])
      → Γ ⊩⟨ l ⟩ A ∷ Univ rU lU ^ [ ! , lU' ] / [U]
      → Γ ⊩⟨ ι lU ⟩ A ^ [ rU , ι lU ]
univ⊩ {lU = lU} {l = l} [U] [A] = irrelevance-≤ (≡is≤ PE.refl) (univEq [U] [A])

univEqTerm : ∀ {Γ A t r l′ ll′}
       → ([U] : Γ ⊩⟨ ∞ ⟩ Univ r l′ ^ [ ! , ll′ ] )
       → ([A] : Γ ⊩⟨ ∞ ⟩ A ∷ Univ r l′ ^ [ ! , ll′ ] / [U])
       → Γ ⊩⟨ ∞ ⟩ t ∷ A ^ [ r , ι l′ ] / maybeEmb (univ⊩ [U] [A])
       → Γ ⊩⟨ ι l′ ⟩ t ∷ A ^ [ r , ι l′ ] / univEq [U] [A]
univEqTerm {Γ} {A} {t} {r} {⁰} [U] [A] [t] = [t]
univEqTerm {Γ} {A} {t} {r} {¹} [U] [A] [t] = [t]

-- Helper function for reducible term equality of type U for specific type derivations.
univEqEq′ : ∀ {l ll l′ Γ X A B} ([U] : Γ ⊩⟨ l ⟩U X ^ ll) →
            let r = toTypeInfo (U-Relevance-Level [U])
            in
              ([A] : Γ ⊩⟨ l′ ⟩ A ^ r)
              → Γ ⊩⟨ l ⟩ A ≡ B ∷ X ^ [ ! , ll ] / U-intr [U]
              → Γ ⊩⟨ l′ ⟩ A ≡ B  ^ r / [A]
univEqEq′ {l} {ll} {l″} {Γ} {X} {A} {B} (noemb (Uᵣ r l′ l< eq [[ ⊢A , ⊢B , D ]])) [A]
          (Uₜ₌ (Uₜ K d typeK K≡K [t]) [u] A≡B [t≡u]) =
  let ⊢Γ = wf ⊢A in
  irrelevanceEq″ (Definition.Untyped.Properties.wk-id A) (Definition.Untyped.Properties.wk-id B) PE.refl PE.refl
    (emb l< ([t] Definition.Typed.Weakening.id ⊢Γ)) [A]
    ([t≡u] Definition.Typed.Weakening.id ⊢Γ)
univEqEq′ (emb emb< X) [A] [A≡B] = univEqEq′ X [A] [A≡B]
univEqEq′ (emb ∞< X) [A] [A≡B] = univEqEq′ X [A] [A≡B]

UnivNotℕ : ∀ {Γ r ll} →  Γ ⊩ℕ Univ r ll → ⊥
UnivNotℕ {ll = ⁰} [[ ⊢A , ⊢B , D ]] = U≢ℕ (whrDet* (id (univ (univ 0<1 (wf ⊢A))) , Uₙ) (D , ℕₙ))
UnivNotℕ {ll = ¹} [[ ⊢A , ⊢B , D ]] = U≢ℕ (whrDet* (id (Uⱼ (wf ⊢A)) , Uₙ) (D , ℕₙ))

UnivNotΠ : ∀ {Γ r r' lΠ l ll} → (l LogRel.⊩¹Π logRelRec l ^[ Γ , Univ r ll ]) r' lΠ → ⊥
UnivNotΠ {ll = ⁰} (Πᵣ rF lF lG _ _ F G D ⊢F ⊢G A≡A [F] [G] G-ext) = U≢Π (whrDet* (id (univ (univ 0<1 (wf ⊢F))) , Uₙ) (red D , Πₙ))
UnivNotΠ {ll = ¹} (Πᵣ rF lF lG _ _ F G D ⊢F ⊢G A≡A [F] [G] G-ext) = U≢Π (whrDet* (id (Uⱼ (wf ⊢F)) , Uₙ) (red D , Πₙ))

U-Relevance-Level-eq : ∀ {l Γ r ll ll'} ([U] : Γ ⊩⟨ l ⟩ Univ r ll ^ [ ! , ll' ]) → U-Relevance-Level (U-elim [U]) PE.≡ (r , ll)
U-Relevance-Level-eq {ll = ⁰} (Uᵣ (Uᵣ r ⁰ l< eq d)) = ×-eq (Univ-PE-injectivity (whrDet* (red d , Uₙ) (id (univ (univ 0<1 (wf (_⊢_:⇒*:_^_.⊢A d)))) , Uₙ)))
U-Relevance-Level-eq {ll = ¹} (Uᵣ (Uᵣ r ⁰ l< eq d)) = let _ , X = (Univ-PE-injectivity (whrDet* (red d , Uₙ) (id (Uⱼ (wf (_⊢_:⇒*:_^_.⊢A d))) , Uₙ))) in ⊥-elim (⁰≢¹ X)
U-Relevance-Level-eq {ll = ¹} (Uᵣ (Uᵣ r ¹ l< eq d)) = ×-eq (Univ-PE-injectivity (whrDet* (red d , Uₙ) (id (Uⱼ (wf (_⊢_:⇒*:_^_.⊢A d))) , Uₙ)))
U-Relevance-Level-eq (ℕᵣ X) = ⊥-elim (UnivNotℕ X)
U-Relevance-Level-eq (ne′ K D neK K≡K) = ⊥-elim (U≢ne neK (whnfRed* (red D) Uₙ))
U-Relevance-Level-eq (Πᵣ X) = ⊥-elim (UnivNotΠ X)
U-Relevance-Level-eq {ι ¹} (emb l< (ℕᵣ X)) = ⊥-elim (UnivNotℕ X)
U-Relevance-Level-eq {ι ¹} (emb l< (ne′ K D neK K≡K)) = ⊥-elim (U≢ne neK (whnfRed* (red D) Uₙ))
U-Relevance-Level-eq {ι ¹} (emb l< (Πᵣ X)) = ⊥-elim (UnivNotΠ X)
U-Relevance-Level-eq {∞} {ll = ⁰} (emb ∞< (Uᵣ (Uᵣ r ⁰ l<₁ eq d))) = ×-eq (Univ-PE-injectivity (whrDet* (red d , Uₙ) (id (univ (univ 0<1 (wf (_⊢_:⇒*:_^_.⊢A d)))) , Uₙ)))
U-Relevance-Level-eq {∞} {ll = ¹} (emb ∞< (Uᵣ (Uᵣ r ⁰ l<₁ eq d))) = let _ , X = (Univ-PE-injectivity (whrDet* (red d , Uₙ) (id (Uⱼ (wf (_⊢_:⇒*:_^_.⊢A d))) , Uₙ))) in ⊥-elim (⁰≢¹ X)
U-Relevance-Level-eq {∞} {ll = ¹} (emb ∞< (Uᵣ (Uᵣ r ¹ l<₁ eq d))) = ×-eq (Univ-PE-injectivity (whrDet* (red d , Uₙ) (id (Uⱼ (wf (_⊢_:⇒*:_^_.⊢A d))) , Uₙ)))
U-Relevance-Level-eq {∞} (emb {l′ = ι ¹} l< (ℕᵣ X)) = ⊥-elim (UnivNotℕ X)
U-Relevance-Level-eq {∞} (emb {l′ = ι ¹} l< (ne′ K D neK K≡K)) = ⊥-elim (U≢ne neK (whnfRed* (red D) Uₙ))
U-Relevance-Level-eq {∞} (emb {l′ = ι ¹} l< (Πᵣ x)) = ⊥-elim (UnivNotΠ x)
U-Relevance-Level-eq {∞} (emb {l′ = ι ¹} l< (emb {l′ = ι ⁰} emb< (ℕᵣ x))) = ⊥-elim (UnivNotℕ x)
U-Relevance-Level-eq {∞} (emb {l′ = ι ¹} l< (emb {l′ = ι ⁰} emb< (ne′ K D neK K≡K))) = ⊥-elim (U≢ne neK (whnfRed* (red D) Uₙ))
U-Relevance-Level-eq {∞} (emb {l′ = ι ¹} l< (emb {l′ = ι ⁰} emb< (Πᵣ x))) = ⊥-elim (UnivNotΠ x)

helper-eq : ∀ {l Γ A B r r'} {[A] : Γ ⊩⟨ l ⟩ A ^ r} (e : r PE.≡ r' ) → Γ ⊩⟨ l ⟩ A ≡ B ^ r' / (PE.subst _ e [A]) → Γ ⊩⟨ l ⟩ A ≡ B ^ r / [A]
helper-eq PE.refl X = X

-- Reducible term equality of type U is reducible type equality.
univEqEq : ∀ {l l′ Γ A B r ll} ([U] : Γ ⊩⟨ l ⟩ Univ r ll ^ [ ! , next ll ]) ([A] : Γ ⊩⟨ l′ ⟩ A ^ [ r , ι ll ])
         → Γ ⊩⟨ l ⟩ A ≡ B ∷ Univ r ll ^ [ ! , next ll ] / [U]
         → Γ ⊩⟨ l′ ⟩ A ≡ B ^ [ r , ι ll ] / [A]
univEqEq {l} {l′} {Γ} {A} {B} {r} {ll} [U] [A] [A≡B] =
  let [A≡B]′ = irrelevanceEqTerm [U] (U-intr (U-elim [U])) [A≡B]
      X = univEqEq′ (U-elim [U]) (PE.subst (λ r → Γ ⊩⟨ l′ ⟩ A ^ r) (PE.sym (PE.cong toTypeInfo (U-Relevance-Level-eq [U]))) [A]) [A≡B]′
  in helper-eq (PE.sym (PE.cong toTypeInfo (U-Relevance-Level-eq [U]))) X

univEqEqTerm : ∀ {Γ A t u r l′ ll}
             → ([U] : Γ ⊩⟨ ∞ ⟩ Univ r l′ ^ [ ! , ll ] )
             → ([A] : Γ ⊩⟨ ∞ ⟩ A ∷ Univ r l′ ^ [ ! , ll ] / [U])
             → Γ ⊩⟨ ∞ ⟩ t ∷ A ^ [ r , ι l′ ] / maybeEmb (univ⊩ [U] [A])
             → Γ ⊩⟨ ∞ ⟩ t ≡ u ∷ A ^ [ r , ι l′ ] / maybeEmb (univ⊩ [U] [A])
             → Γ ⊩⟨ ι l′ ⟩ t ≡ u ∷ A ^ [ r , ι l′ ] / univEq [U] [A]
univEqEqTerm {Γ} {A} {t} {u} {r} {⁰} [U] [A] [t] [t≡u] = [t≡u]
univEqEqTerm {Γ} {A} {t} {u} {r} {¹} [U] [A] [t] [t≡u] = [t≡u]

un-univEq : ∀ {l Γ A r }
          → ([A] : Γ ⊩⟨ ι l ⟩ A ^ [ r , ι l ])
          → let [U] : Γ ⊩⟨ next l ⟩ Univ r l ^ [ ! , next l ]
                [U] = Ugen (wf (escape [A]))
            in Γ ⊩⟨ next l ⟩ A ∷ Univ r l ^ [ ! , next l ] / [U]
un-univEq {⁰} {Γ} {A} {.!} (ℕᵣ [[ ⊢A , ⊢ℕ , D ]] ) = Uₜ ℕ (un-univ:⇒*: [[ ⊢A , ⊢ℕ , D ]]) ℕₙ (≅ₜ-ℕrefl (wf ⊢A)) (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (ℕᵣ [[ ⊢A , ⊢ℕ , D ]] ))
un-univEq {⁰} {Γ} {A} {.%} (Emptyᵣ [[ ⊢A , ⊢Empty , D ]]) = Uₜ (Empty ⁰) (un-univ:⇒*: [[ ⊢A , ⊢Empty , D ]]) Emptyₙ (≅ₜ-Emptyrefl (wf ⊢A))
                                                                                (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (Emptyᵣ [[ ⊢A , ⊢Empty , D ]] ))
un-univEq {⁰} {Γ} {A} {r} (ne′ K D neK K≡K) = Uₜ K (un-univ:⇒*: D) (ne neK) (~-to-≅ₜ K≡K) (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (ne′ K D neK K≡K))
un-univEq {⁰} {Γ} {A} {r} (Πᵣ′ rF .⁰ .⁰ (≡is≤ PE.refl) (≡is≤ PE.refl) F G D ⊢F ⊢G A≡A [F] [G] G-ext) =
  Uₜ (Π F ^ rF ° ⁰ ▹ G ° ⁰ ° ⁰) (un-univ:⇒*: D) Πₙ (≅-un-univ A≡A) λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (Πᵣ′ rF ⁰ ⁰ (≡is≤ PE.refl) (≡is≤ PE.refl) F G D ⊢F ⊢G A≡A [F] [G] G-ext)
un-univEq {⁰}  {Γ} {A} {.%} (∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext) =
  Uₜ (∃ F ▹ G) (un-univ:⇒*: D) ∃ₙ (≅-un-univ A≡A) λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
un-univEq {¹} {Γ} {A} {.!} (Uᵣ (Uᵣ r .⁰ emb< eq [[ ⊢A , ⊢B , D ]])) = Uₜ (Univ r ⁰) (un-univ:⇒*: [[ ⊢A , ⊢B , D ]]) Uₙ (≅-U⁰refl (wf ⊢A))
                                                                              (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (Uᵣ (Uᵣ r ⁰ emb< eq [[ ⊢A , ⊢B , D ]] )))
un-univEq {¹} {Γ} {A} {.%} (Emptyᵣ [[ ⊢A , ⊢Empty , D ]]) = Uₜ (Empty ¹) (un-univ:⇒*: [[ ⊢A , ⊢Empty , D ]]) Emptyₙ (≅ₜ-Emptyrefl (wf ⊢A))
                                                                                (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (Emptyᵣ [[ ⊢A , ⊢Empty , D ]] ))
un-univEq {¹} {Γ} {A} {r} (ne′ K D neK K≡K) = Uₜ K (un-univ:⇒*: D) (ne neK) (~-to-≅ₜ K≡K) (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (ne′ K D neK K≡K))
un-univEq {¹} {Γ} {A} {r} (Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext) =
  Uₜ (Π F ^ rF ° lF ▹ G ° lG ° ¹ ) (un-univ:⇒*: D) Πₙ (≅-un-univ A≡A) λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext)
un-univEq {¹} {Γ} {A} {.%} (∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext) =
  Uₜ (∃ F ▹ G) (un-univ:⇒*: D) ∃ₙ (≅-un-univ A≡A) λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
un-univEq {¹} {Γ} {A} {.%} (emb emb< (Emptyᵣ [[ ⊢A , ⊢Empty , D ]])) = Uₜ (Empty ¹) (un-univ:⇒*: [[ ⊢A , ⊢Empty , D ]]) Emptyₙ (≅ₜ-Emptyrefl (wf ⊢A))
                                                                                (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (Emptyᵣ [[ ⊢A , ⊢Empty , D ]] ))
un-univEq {¹} {Γ} {A} {r} (emb emb< (ne′ K D neK K≡K)) = Uₜ K (un-univ:⇒*: D) (ne neK) (~-to-≅ₜ K≡K) (λ [ρ] ⊢Δ → Lwk.wk [ρ] ⊢Δ (ne′ K D neK K≡K))
un-univEq {¹} {Γ} {A} {r} (emb emb< (Πᵣ′ rF lF lG lF≤ lG≤ F G D ⊢F ⊢G A≡A [F] [G] G-ext)) =
  Uₜ (Π F ^ rF ° lF ▹ G ° lG ° ¹) (un-univ:⇒*: D) Πₙ (≅-un-univ A≡A) λ [ρ] ⊢Δ → let X = Lwk.wk [ρ] ⊢Δ (Πᵣ′ rF lF lG lF≤ lG≤ F G D ⊢F ⊢G A≡A [F] [G] G-ext) in maybeEmb′ (<is≤ 0<1) X
un-univEq {¹} {Γ} {A} {.%} (emb emb< (∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext)) =
  Uₜ (∃ F ▹ G) (un-univ:⇒*: D) ∃ₙ (≅-un-univ A≡A) λ [ρ] ⊢Δ → let X = Lwk.wk [ρ] ⊢Δ (∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext) in maybeEmb′ (<is≤ 0<1) X

un-univEqEq-Shape : ∀ {l Γ A B r }
          ([A] : Γ ⊩⟨ ι l ⟩ A ^ [ r , ι l ]) ([B] : Γ ⊩⟨ ι l ⟩ B ^ [ r , ι l ])
          (ShapeA : ShapeView Γ (ι l) (ι l) A B [ r , ι l ] [ r , ι l ] [A] [B])
          ([A≡B] : Γ ⊩⟨ ι l ⟩ A ≡ B ^ [ r , ι l ] / [A])
          → let [U] : Γ ⊩⟨ next l ⟩ Univ r l ^ [ ! , next l ]
                [U] = Ugen (wf (escape [A]))
            in Γ ⊩⟨ next l ⟩ A ≡ B ∷ Univ r l ^ [ ! , next l ] / [U]
un-univEqEq-Shape {⁰} {Γ} {A} {B} {.!} _ _ (ℕᵥ [[ ⊢A , ⊢ℕ , D ]] ℕB) [A≡B] =
  let [A] = ℕᵣ [[ ⊢A , ⊢ℕ , D ]]
      [B] = ℕᵣ [[ redFirst* [A≡B] , ⊢ℕ , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ⁰} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-ℕrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {⁰} {Γ} {A} {B} {.%} _ _ (Emptyᵥ [[ ⊢A , ⊢Empty , D ]] EmptyB) [A≡B] =
  let [A] = Emptyᵣ [[ ⊢A , ⊢Empty , D ]]
      [B] = Emptyᵣ [[ redFirst* [A≡B] , ⊢Empty , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ⁰} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-Emptyrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {⁰} {Γ} {A} {B} {r} _ _  (ne (ne K D neK K≡K) neB) (ne₌ M D′ neM K≡M) =
  let [A] = ne′ K D neK K≡K
      [B] = ne′ M D′ neM (~-trans (~-sym K≡M) K≡M)
      [A≡B] = ne₌ M D′ neM K≡M
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ⁰} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (~-to-≅ₜ K≡M) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {⁰} {Γ} {A} {B} {r} _ _ (Πᵥ (Πᵣ rF .⁰ .⁰ (≡is≤ PE.refl) (≡is≤ PE.refl) F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (Πᵣ rF' .⁰ .⁰ (≡is≤ PE.refl) (≡is≤ PE.refl) F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))
                                    (Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = Πᵣ′ rF ⁰ ⁰ (≡is≤ PE.refl) (≡is≤ PE.refl) F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = Πᵣ′ rF' ⁰ ⁰ (≡is≤ PE.refl) (≡is≤ PE.refl) F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , rF≡rF , _ , G≡G , _ = Π-PE-injectivity (whrDet* (D′ , Whnf.Πₙ) (red D' , Whnf.Πₙ))
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ⁰} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ Π F ^ rF ° ⁰ ▹ G ° ⁰ ° _ ≅  Π F' ^ rF' ° ⁰ ▹ X ° ⁰ ° _ ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ Π F ^ rF ° ⁰ ▹ G ° ⁰ ° _ ≅  Π X ^ rF' ° ⁰ ▹ G′ ° ⁰ ° _ ^ _ ) F≡F
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° ⁰ ▹ G ° ⁰ ° _ ≅  Π F′ ^ X ° ⁰ ▹ G′ ° ⁰ ° _ ^ _ ) rF≡rF A≡B)))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]

un-univEqEq-Shape {⁰} {Γ} {A} {B} {.%} _ _ (∃ᵥ (∃ᵣ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (∃ᵣ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))
                                    (∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = ∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = ∃ᵣ′ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = ∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , G≡G  = ∃-PE-injectivity (whrDet* (D′ , Whnf.∃ₙ) (red D' , Whnf.∃ₙ))
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ⁰} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ F' ▹ X ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ X ▹ G′ ^ _ ) F≡F A≡B))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.!} _ _ (Uᵥ (Uᵣ r .⁰ emb< eq d) (Uᵣ r₁ .⁰ emb< eq₁ d₁)) [A≡B] =
  let [A] = Uᵣ (Uᵣ r ⁰ emb< eq d)
      [B] = Uᵣ (Uᵣ r₁ ⁰ emb< eq₁ d₁)
      [[ ⊢A , _ , _ ]] = d
      r≡r , _ = Univ-PE-injectivity (whrDet* (red d₁ , Whnf.Uₙ) ([A≡B] , Whnf.Uₙ))
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (PE.subst (λ X → _ ⊢  Univ r ⁰ ≅ Univ X ⁰ ∷ U _ ^ _ ) (PE.sym r≡r) (≅-U⁰refl (wf ⊢A))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (Emptyᵥ [[ ⊢A , ⊢Empty , D ]] EmptyB) [A≡B] =
  let [A] = Emptyᵣ [[ ⊢A , ⊢Empty , D ]]
      [B] = Emptyᵣ [[ redFirst* [A≡B] , ⊢Empty , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-Emptyrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _  (ne (ne K D neK K≡K) neB) (ne₌ M D′ neM K≡M) =
  let [A] = ne′ K D neK K≡K
      [B] = ne′ M D′ neM (~-trans (~-sym K≡M) K≡M)
      [A≡B] = ne₌ M D′ neM K≡M
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (~-to-≅ₜ K≡M) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (Πᵥ (Πᵣ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (Πᵣ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))
                                    (Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = Πᵣ′ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , rF≡rF , lF≡lF , G≡G , lG≡lG , _ = Π-PE-injectivity (whrDet* (D′ , Whnf.Πₙ) (red D' , Whnf.Πₙ))
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F' ^ rF' ° lF' ▹ X ° lG' ° _ ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π X ^ rF' ° lF' ▹ G′ ° lG' ° _ ^ _ ) F≡F
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° lF' ▹ G′ ° X ° _ ^ _ ) lG≡lG
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° X ▹ G′ ° lG ° _ ^ _ ) lF≡lF
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ X ° lF ▹ G′ ° lG ° _ ^ _ ) rF≡rF A≡B)))))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (∃ᵥ (∃ᵣ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (∃ᵣ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))
                                    (∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = ∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = ∃ᵣ′ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = ∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , G≡G  = ∃-PE-injectivity (whrDet* (D′ , Whnf.∃ₙ) (red D' , Whnf.∃ₙ))
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ F' ▹ X ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ X ▹ G′ ^ _ ) F≡F A≡B))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb⁰¹ (Emptyᵥ [[ ⊢A , ⊢Empty , D ]] EmptyB)) [A≡B] =
  let [A] = Emptyᵣ [[ ⊢A , ⊢Empty , D ]]
      [B] = Emptyᵣ [[ redFirst* [A≡B] , ⊢Empty , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-Emptyrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb⁰¹ (ne (ne K D neK K≡K) neB)) (ne₌ M D′ neM K≡M) =
  let [A] = ne′ K D neK K≡K
      [B] = ne′ M D′ neM (~-trans (~-sym K≡M) K≡M)
      [A≡B] = ne₌ M D′ neM K≡M
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (~-to-≅ₜ K≡M) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb⁰¹ (Πᵥ (Πᵣ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (Πᵣ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext')))
                                    (Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = Πᵣ′ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , rF≡rF , lF≡lF , G≡G , lG≡lG , _ = Π-PE-injectivity (whrDet* (D′ , Whnf.Πₙ) (red D' , Whnf.Πₙ))
  in Uₜ₌ (un-univEq (maybeEmb′ (<is≤ 0<1) [A])) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F' ^ rF' ° lF' ▹ X ° lG' ° _ ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π X ^ rF' ° lF' ▹ G′ ° lG' ° _ ^ _ ) F≡F
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° lF' ▹ G′ ° X ° _ ^ _ ) lG≡lG
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° X ▹ G′ ° lG ° _ ^ _ ) lF≡lF
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ X ° lF ▹ G′ ° lG ° _ ^ _ ) rF≡rF A≡B)))))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb⁰¹ (∃ᵥ (∃ᵣ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (∃ᵣ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext')))
                                    (∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = ∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = ∃ᵣ′ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = ∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , G≡G  = ∃-PE-injectivity (whrDet* (D′ , Whnf.∃ₙ) (red D' , Whnf.∃ₙ))
  in Uₜ₌ (un-univEq (maybeEmb′ (<is≤ 0<1) [A])) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ F' ▹ X ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ X ▹ G′ ^ _ ) F≡F A≡B))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb⁰¹ (emb¹⁰ (Emptyᵥ [[ ⊢A , ⊢Empty , D ]] EmptyB))) [A≡B] =
  let [A] = Emptyᵣ [[ ⊢A , ⊢Empty , D ]]
      [B] = Emptyᵣ [[ redFirst* [A≡B] , ⊢Empty , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-Emptyrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb⁰¹ (emb¹⁰ (ne (ne K D neK K≡K) neB))) (ne₌ M D′ neM K≡M) =
  let [A] = ne′ K D neK K≡K
      [B] = ne′ M D′ neM (~-trans (~-sym K≡M) K≡M)
      [A≡B] = ne₌ M D′ neM K≡M
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (~-to-≅ₜ K≡M) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb⁰¹ (emb¹⁰ (Πᵥ (Πᵣ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (Πᵣ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))))
                                    (Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = Πᵣ′ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , rF≡rF , lF≡lF , G≡G , lG≡lG , _ = Π-PE-injectivity (whrDet* (D′ , Whnf.Πₙ) (red D' , Whnf.Πₙ))
  in Uₜ₌ (un-univEq (maybeEmb′ (<is≤ 0<1) [A])) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq (maybeEmb′ (<is≤ 0<1) [B])))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F' ^ rF' ° lF' ▹ X ° lG' ° _ ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π X ^ rF' ° lF' ▹ G′ ° lG' ° _ ^ _ ) F≡F
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° lF' ▹ G′ ° X ° _ ^ _ ) lG≡lG
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° X ▹ G′ ° lG ° _ ^ _ ) lF≡lF
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ X ° lF ▹ G′ ° lG ° _ ^ _ ) rF≡rF A≡B)))))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb⁰¹ (emb¹⁰ (∃ᵥ (∃ᵣ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (∃ᵣ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))))
                                    (∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = ∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = ∃ᵣ′ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = ∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , G≡G  = ∃-PE-injectivity (whrDet* (D′ , Whnf.∃ₙ) (red D' , Whnf.∃ₙ))
  in Uₜ₌ (un-univEq (maybeEmb′ (<is≤ 0<1) [A])) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq (maybeEmb′ (<is≤ 0<1) [B])))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ F' ▹ X ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ X ▹ G′ ^ _ ) F≡F A≡B))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb¹⁰ (Emptyᵥ [[ ⊢A , ⊢Empty , D ]] EmptyB)) [A≡B] =
  let [A] = Emptyᵣ [[ ⊢A , ⊢Empty , D ]]
      [B] = Emptyᵣ [[ redFirst* [A≡B] , ⊢Empty , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-Emptyrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb¹⁰ (ne (ne K D neK K≡K) neB)) (ne₌ M D′ neM K≡M) =
  let [A] = ne′ K D neK K≡K
      [B] = ne′ M D′ neM (~-trans (~-sym K≡M) K≡M)
      [A≡B] = ne₌ M D′ neM K≡M
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (~-to-≅ₜ K≡M) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb¹⁰ (Πᵥ (Πᵣ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (Πᵣ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext')))
                                    (Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = Πᵣ′ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , rF≡rF , lF≡lF , G≡G , lG≡lG , _ = Π-PE-injectivity (whrDet* (D′ , Whnf.Πₙ) (red D' , Whnf.Πₙ))
  in Uₜ₌ (un-univEq [A] ) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq (maybeEmb′ (<is≤ 0<1) [B])))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F' ^ rF' ° lF' ▹ X ° lG' ° _ ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π X ^ rF' ° lF' ▹ G′ ° lG' ° _ ^ _ ) F≡F
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° lF' ▹ G′ ° X ° _ ^ _ ) lG≡lG
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° X ▹ G′ ° lG ° _ ^ _ ) lF≡lF
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ X ° lF ▹ G′ ° lG ° _ ^ _ ) rF≡rF A≡B)))))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb¹⁰ (∃ᵥ (∃ᵣ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                         (∃ᵣ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext')))
                                    (∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = ∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = ∃ᵣ′ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = ∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , G≡G  = ∃-PE-injectivity (whrDet* (D′ , Whnf.∃ₙ) (red D' , Whnf.∃ₙ))
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq (maybeEmb′ (<is≤ 0<1) [B])))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ F' ▹ X ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ X ▹ G′ ^ _ ) F≡F A≡B))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb¹⁰ (emb⁰¹ (Emptyᵥ [[ ⊢A , ⊢Empty , D ]] EmptyB))) [A≡B] =
  let [A] = Emptyᵣ [[ ⊢A , ⊢Empty , D ]]
      [B] = Emptyᵣ [[ redFirst* [A≡B] , ⊢Empty , [A≡B] ]]
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (≅ₜ-Emptyrefl (wf ⊢A)) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb¹⁰ (emb⁰¹ (ne (ne K D neK K≡K) neB))) (ne₌ M D′ neM K≡M) =
  let [A] = ne′ K D neK K≡K
      [B] = ne′ M D′ neM (~-trans (~-sym K≡M) K≡M)
      [A≡B] = ne₌ M D′ neM K≡M
  in Uₜ₌ (un-univEq [A]) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq [B]))
         (~-to-≅ₜ K≡M) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {r} _ _ (emb¹⁰ (emb⁰¹ (Πᵥ (Πᵣ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (Πᵣ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))))
                                    (Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = Πᵣ′ rF lF lG lF< lG< F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = Πᵣ′ rF' lF' lG' lF<' lG<' F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = Π₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , rF≡rF , lF≡lF , G≡G , lG≡lG , _ = Π-PE-injectivity (whrDet* (D′ , Whnf.Πₙ) (red D' , Whnf.Πₙ))
  in Uₜ₌ (un-univEq (maybeEmb′ (<is≤ 0<1) [A])) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq (maybeEmb′ (<is≤ 0<1) [B])))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG  ° _ ≅  Π F' ^ rF' ° lF' ▹ X ° lG' ° _ ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π X ^ rF' ° lF' ▹ G′ ° lG' ° _ ^ _ ) F≡F
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° lF' ▹ G′ ° X ° _ ^ _ ) lG≡lG
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ rF' ° X ▹ G′ ° lG ° _ ^ _ ) lF≡lF
             (PE.subst (λ X → _ ⊢ Π F ^ rF ° lF ▹ G ° lG ° _ ≅  Π F′ ^ X ° lF ▹ G′ ° lG ° _  ^ _ ) rF≡rF A≡B)))))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]
un-univEqEq-Shape {¹} {Γ} {A} {B} {.%} _ _ (emb¹⁰ (emb⁰¹ (∃ᵥ (∃ᵣ F G D ⊢F ⊢G A≡A [F] [G] G-ext)
                                        (∃ᵣ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'))))
                                    (∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]) =
  let [A] = ∃ᵣ′ F G D ⊢F ⊢G A≡A [F] [G] G-ext
      [B] = ∃ᵣ′ F' G' D' ⊢F' ⊢G' A≡A' [F'] [G'] G-ext'
      [A≡B] = ∃₌ F′ G′ D′ A≡B [F≡F′] [G≡G′]
      F≡F , G≡G  = ∃-PE-injectivity (whrDet* (D′ , Whnf.∃ₙ) (red D' , Whnf.∃ₙ))
  in Uₜ₌ (un-univEq (maybeEmb′ (<is≤ 0<1) [A])) (irrelevanceTerm {l = next ¹} (Ugen (wf (escape [B]))) (Ugen (wf (escape [A]))) (un-univEq (maybeEmb′ (<is≤ 0<1) [B])))
         (≅-un-univ (
           PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ F' ▹ X ^ _ ) G≡G
           (PE.subst (λ X → _ ⊢ ∃ F ▹ G ≅  ∃ X ▹ G′ ^ _ ) F≡F A≡B))) λ [ρ] ⊢Δ → Lwk.wkEq [ρ] ⊢Δ [A] [A≡B]

un-univEqEq : ∀ {l Γ A B r }
          ([A] : Γ ⊩⟨ ι l ⟩ A ^ [ r , ι l ]) ([B] : Γ ⊩⟨ ι l ⟩ B ^ [ r , ι l ])
          ([A≡B] : Γ ⊩⟨ ι l ⟩ A ≡ B ^ [ r , ι l ] / [A])
          → let [U] : Γ ⊩⟨ next l ⟩ Univ r l ^ [ ! , next l ]
                [U] = Ugen (wf (escape [A]))
            in Γ ⊩⟨ next l ⟩ A ≡ B ∷ Univ r l ^ [ ! , next l ] / [U]
un-univEqEq [A] [B] [A≡B] = un-univEqEq-Shape [A] [B] (goodCases [A] [B] [A≡B]) [A≡B]


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

open import lib.Basics
open import lib.NConnected
open import lib.NType2
open import lib.cubical.Square
open import lib.types.Lift
open import lib.types.Nat
open import lib.types.Pointed
open import lib.types.Sigma
open import lib.types.TLevel
open import lib.types.Truncation
open import lib.types.Unit

{- Sequential colimits -}

module lib.types.NatColim where

module _ {i} {D : ℕ → Type i} where

  private
    data #ℕColim-aux (d : (n : ℕ) → D n → D (S n)) : Type i where
      #ncin : (n : ℕ) → D n → #ℕColim-aux d

    data #ℕColim (d : (n : ℕ) → D n → D (S n)) : Type i where
      #ncolim : #ℕColim-aux d → (Unit → Unit) → #ℕColim d

  ℕColim : (d : (n : ℕ) → D n → D (S n)) → Type i
  ℕColim d = #ℕColim d

  ncin : {d : (n : ℕ) → D n → D (S n)} → (n : ℕ) → D n → ℕColim d
  ncin n x = #ncolim (#ncin n x) _

  postulate  -- HIT
    ncglue : {d : (n : ℕ) → D n → D (S n)}
      (n : ℕ) → (x : D n) → ncin {d = d} n x == ncin (S n) (d n x)

  module ℕColimElim (d : (n : ℕ) → D n → D (S n))
    {j} {P : ℕColim d → Type j}
    (ncin* : (n : ℕ) (x : D n) → P (ncin n x))
    (ncglue* : (n : ℕ) (x : D n)
      → ncin* n x == ncin* (S n) (d n x) [ P ↓ ncglue n x ])
    where

    f : Π (ℕColim d) P
    f = f-aux phantom where

      f-aux : Phantom ncglue* → Π (ℕColim d) P
      f-aux phantom (#ncolim (#ncin n x) _) = ncin* n x

    postulate  -- HIT
      ncglue-β : (n : ℕ) (x : D n) → apd f (ncglue n x) == ncglue* n x

  open ℕColimElim public using () renaming (f to ℕColim-elim)

  module ℕColimRec (d : (n : ℕ) → D n → D (S n))
    {j} {A : Type j}
    (ncin* : (n : ℕ) → D n → A)
    (ncglue* : (n : ℕ) → (x : D n) → ncin* n x == ncin* (S n) (d n x))
    where

    private
      module M = ℕColimElim d ncin* (λ n x → ↓-cst-in (ncglue* n x))

    f : ℕColim d → A
    f = M.f

    ncglue-β : (n : ℕ) (x : D n) → ap f (ncglue n x) == ncglue* n x
    ncglue-β n x = apd=cst-in {f = f} (M.ncglue-β n x)

⊙ℕColim : ∀ {i} {D : ℕ → Ptd i} (d : (n : ℕ) → fst (D n ⊙→ D (S n))) → Ptd i
⊙ℕColim {D = D} d = ⊙[ ℕColim (fst ∘ d) , ncin 0 (snd (D 0)) ]

{- Can define a function [nc-raise d : ℕColim d → ℕColim d]
   so that [inn (S n) ∘ d = nc-raise d ∘ inn n] -}

module ℕCRaise {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n)) =
  ℕColimRec d {A = ℕColim d}
    (λ n x → ncin (S n) (d n x))
    (λ n x → ncglue (S n) (d n x))

nc-raise : ∀ {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n))
  → ℕColim d → ℕColim d
nc-raise d = ℕCRaise.f d

nc-raise-= : ∀ {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n)) (c : ℕColim d)
  → c == nc-raise d c
nc-raise-= d = ℕColimElim.f d
  (λ n x → ncglue n x)
  (λ n x → ↓-='-from-square $
    ap-idf (ncglue n x) ∙v⊡ connection2 ⊡v∙ (! (ℕCRaise.ncglue-β d n x)))

{- Lift an element of D₀ to any level -}

nc-lift : ∀ {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n))
  (n : ℕ) → D O → D n
nc-lift d O x = x
nc-lift d (S n) x = d n (nc-lift d n x)

nc-lift-= : ∀ {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n))
  (n : ℕ) (x : D O)
  → ncin {d = d} O x == ncin n (nc-lift d n x)
nc-lift-= d O x = idp
nc-lift-= d (S n) x = nc-lift-= d n x ∙ ncglue n (nc-lift d n x)

{- Lift an element of D₀ to the 'same level' as some element of ℕColim d -}

module ℕCMatch {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n)) (x : D O) =
  ℕColimRec d {A = ℕColim d}
    (λ n _ → ncin n (nc-lift d n x))
    (λ n _ → ncglue n (nc-lift d n x))

nc-match = ℕCMatch.f

nc-match-=-base : ∀ {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n))
  (x : D O) (c : ℕColim d)
  → ncin O x == nc-match d x c
nc-match-=-base d x = ℕColimElim.f d
  (λ n _ → nc-lift-= d n x)
  (λ n y → ↓-cst=app-from-square $
    disc-to-square idp ⊡v∙ ! (ℕCMatch.ncglue-β d x n y))

{- If all Dₙ are m-connected, then the colim is m-connected -}

ncolim-conn : ∀ {i} {D : ℕ → Type i} (d : (n : ℕ) → D n → D (S n)) (m : ℕ₋₂)
  → ((n : ℕ) → is-connected m (D n))
  → is-connected m (ℕColim d)
ncolim-conn {D = D} d ⟨-2⟩ cD = -2-conn (ℕColim d)
ncolim-conn {D = D} d (S m) cD =
  Trunc-rec (prop-has-level-S is-contr-is-prop)
    (λ x → ([ ncin O x ] ,
            (Trunc-elim (λ _ → =-preserves-level _ Trunc-level) $
              λ c → ap [_] (nc-match-=-base d x c) ∙ nc-match-=-point x c)))
    (fst (cD O))
  where
  nc-match-=-point : (x : D O) (c : ℕColim d)
    → [_] {n = S m} (nc-match d x c) == [ c ]
  nc-match-=-point x = ℕColimElim.f d
    (λ n y → ap (Trunc-fmap (ncin n))
                (contr-has-all-paths (cD n) [ nc-lift d n x ] [ y ]))
      (λ n y → ↓-='-from-square $
        (ap-∘ [_] (nc-match d x) (ncglue n y)
         ∙ ap (ap [_]) (ℕCMatch.ncglue-β d x n y))
        ∙v⊡
        ! (ap-idf _)
        ∙h⊡
        (square-symmetry $
          natural-square
            (Trunc-elim (λ _ → =-preserves-level _ Trunc-level)
               (λ c → ap [_] (nc-raise-= d c)))
            (ap (Trunc-fmap (ncin n))
                (contr-has-all-paths (cD n) [ nc-lift d n x ] [ y ])))
        ⊡h∙
        (∘-ap (Trunc-fmap (nc-raise d)) (Trunc-fmap (ncin n))
              (contr-has-all-paths (cD n) [ nc-lift d n x ] [ y ])
         ∙ vert-degen-path
             (natural-square
               (λ t → Trunc-fmap-∘ (nc-raise d) (ncin n) t
                      ∙ ! (Trunc-fmap-∘ (ncin (S n)) (d n) t))
               (contr-has-all-paths (cD n) [ nc-lift d n x ] [ y ]))
         ∙ ap-∘ (Trunc-fmap (ncin (S n))) (Trunc-fmap (d n))
                (contr-has-all-paths (cD n) [ nc-lift d n x ] [ y ])
         ∙ ap (ap (Trunc-fmap (ncin (S n))))
              (contr-has-all-paths (=-preserves-level _ (cD (S n))) _ _)))

{- Type of finite tuples -}

FinTuplesType : ∀ {i} → (ℕ → Ptd i) → ℕ → Ptd i
FinTuplesType F O = ⊙Lift ⊙Unit
FinTuplesType F (S n) = F O ⊙× FinTuplesType (F ∘ S) n

fin-tuples-map : ∀ {i} (F : ℕ → Ptd i) (n : ℕ)
  → fst (FinTuplesType F n ⊙→ FinTuplesType F (S n))
fin-tuples-map F O = (_ , idp)
fin-tuples-map F (S n) =
  ((λ {(x , r) → (x , fst (fin-tuples-map (F ∘ S) n) r)}) ,
   pair×= idp (snd (fin-tuples-map (F ∘ S) n)))

⊙FinTuples : ∀ {i} → (ℕ → Ptd i) → Ptd i
⊙FinTuples {i} F = ⊙ℕColim (fin-tuples-map F)

FinTuples : ∀ {i} → (ℕ → Ptd i) → Type i
FinTuples = fst ∘ ⊙FinTuples

module FinTuplesCons {i} (F : ℕ → Ptd i) where

  module Into (x : fst (F O)) =
    ℕColimRec (fst ∘ fin-tuples-map (F ∘ S)) {A = fst (⊙FinTuples F)}
      (λ n r → ncin (S n) (x , r))
      (λ n r → ncglue (S n) (x , r))

  into = uncurry Into.f

  out-ncin : (n : ℕ)
    → fst (FinTuplesType F n) → fst (F O ⊙× ⊙FinTuples (F ∘ S))
  out-ncin O x = (snd (F O) , ncin O _)
  out-ncin (S n) (x , r) = (x , ncin n r)

  out-ncglue : (n : ℕ) (r : fst (FinTuplesType F n))
    → out-ncin n r == out-ncin (S n) (fst (fin-tuples-map F n) r)
  out-ncglue O x = idp
  out-ncglue (S n) (x , r) = pair= idp (ncglue n r)

  module Out = ℕColimRec _ out-ncin out-ncglue
  out = Out.f

  into-out-ncin : (n : ℕ) (r : fst (FinTuplesType F n))
    → into (out-ncin n r) == ncin n r
  into-out-ncin O x = ! (ncglue O x)
  into-out-ncin (S n) (x , r) = idp

  into-out-ncglue : (n : ℕ) (r : fst (FinTuplesType F n))
    → into-out-ncin n r == into-out-ncin (S n) (fst (fin-tuples-map F n) r)
      [ (λ s → into (out s) == s) ↓ ncglue n r ]
  into-out-ncglue O x =
    ↓-∘=idf-from-square into out $
      ap (ap into) (Out.ncglue-β O x)
      ∙v⊡ bl-square (ncglue O x)
  into-out-ncglue (S n) (x , r) =
    ↓-∘=idf-from-square into out $
      (ap (ap into) (Out.ncglue-β (S n) (x , r))
       ∙ ∘-ap into (_,_ x) (ncglue n r)
       ∙ Into.ncglue-β x n r)
      ∙v⊡ vid-square

  into-out : (r : fst (⊙FinTuples F)) → into (out r) == r
  into-out = ℕColimElim.f _
    into-out-ncin
    into-out-ncglue

  out-into : (t : fst (F O ⊙× ⊙FinTuples (F ∘ S))) → out (into t) == t
  out-into = uncurry $ λ x → ℕColimElim.f _
    (λ n r → idp)
    (λ n r → ↓-='-from-square $
      (ap-∘ out (Into.f x) (ncglue n r)
       ∙ ap (ap out) (Into.ncglue-β x n r)
       ∙ Out.ncglue-β (S n) (x , r))
      ∙v⊡ vid-square)

fin-tuples-cons : ∀ {i} (F : ℕ → Ptd i)
  → fst (F O) × FinTuples (F ∘ S) ≃ FinTuples F
fin-tuples-cons {i} F = equiv into out into-out out-into
  where open FinTuplesCons F

⊙fin-tuples-cons : ∀ {i} (F : ℕ → Ptd i)
  → (F O ⊙× ⊙FinTuples (F ∘ S)) ⊙≃ ⊙FinTuples F
⊙fin-tuples-cons F = ⊙≃-in (fin-tuples-cons F) (! (ncglue O _))


{-# OPTIONS --cubical --no-import-sorts #-}

module Number.Instances.QuoIntFromInt where

open import Agda.Primitive renaming (_⊔_ to ℓ-max; lsuc to ℓ-suc; lzero to ℓ-zero)
open import Cubical.Foundations.Everything hiding (⋆) renaming (_⁻¹ to _⁻¹ᵖ; assoc to ∙-assoc)
open import Cubical.Foundations.Logic renaming (inl to inlᵖ; inr to inrᵖ)

open import Cubical.Relation.Nullary.Base renaming (¬_ to ¬ᵗ_)
open import Cubical.Relation.Binary.Base
open import Cubical.Data.Sum.Base renaming (_⊎_ to infixr 4 _⊎_)
open import Cubical.Data.Sigma.Base renaming (_×_ to infixr 4 _×_)
open import Cubical.Data.Sigma
open import Cubical.Data.Bool as Bool using (Bool; not; true; false)
open import Cubical.Data.Empty renaming (elim to ⊥-elim; ⊥ to ⊥⊥) -- `⊥` and `elim`
open import Cubical.Foundations.Logic renaming (¬_ to ¬ᵖ_; inl to inlᵖ; inr to inrᵖ)
open import Function.Base using (it; _∋_; _$_)
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Univalence

open import Cubical.HITs.PropositionalTruncation --.Properties

open import Utils using (!_; !!_)
open import MoreLogic.Reasoning
open import MoreLogic.Definitions
open import MoreLogic.Properties
open import MorePropAlgebra.Definitions hiding (_≤''_)
open import MorePropAlgebra.Structures
open import MorePropAlgebra.Bundles
open import MorePropAlgebra.Consequences
open import Number.Structures2
open import Number.Bundles2

import Agda.Builtin.Int as Builtin
import Data.Integer.Base as BuiltinBase
import Data.Integer.Properties as BuiltinProps

open import Cubical.Data.Nat.Literals
open import Number.Prelude.Nat
open import Number.Prelude.Int
import Cubical.Data.Int as Int
import Number.Instances.Int

open import Cubical.HITs.Ints.QuoInt as QuoInt using
  ( ℤ
  ; _+_
  ; -_
  ; Int≡ℤ
  ; signed
  ; posneg
  ; ℤ→Int
  ; sucℤ
  ; predℤ
  ; sign
  ; abs
  ; pos
  ; neg
  ; +-comm
  ; +-assoc
  ; sucℤ-+ʳ
  ) renaming
  ( _*_ to _·_ )

ℤ≡Int = sym Int≡ℤ

private
  _·ᵗʳ_ : Int → Int → Int
  _·ᵗʳ_ = transport (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _·_

  ·≡·ᵗʳ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _·_ _·ᵗʳ_
  ·≡·ᵗʳ i = transp (λ j → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j)) (~ i) _·_

  lemma1 : ∀ a b → b +ⁿ a ·ⁿ suc b ≡ a ·ⁿ b +ⁿ (a +ⁿ b)
  lemma1 a b =
    b +ⁿ a ·ⁿ suc b    ≡⟨ (λ i → b +ⁿ ·ⁿ-suc a b i) ⟩
    b +ⁿ (a +ⁿ a ·ⁿ b) ≡⟨ +ⁿ-assoc b a (a ·ⁿ b) ⟩
    (b +ⁿ a) +ⁿ a ·ⁿ b ≡⟨ (λ i → +ⁿ-comm b a i +ⁿ a ·ⁿ b) ⟩
    (a +ⁿ b) +ⁿ a ·ⁿ b ≡⟨ +ⁿ-comm (a +ⁿ b) (a ·ⁿ b) ⟩
    a ·ⁿ b +ⁿ (a +ⁿ b) ∎

  ·ᵗʳ≡'·ᶻ : ∀ a b → a ·ᵗʳ b ≡ a ·ᶻ b
  ·ᵗʳ≡'·ᶻ (posᶻ      0 ) (posᶻ      0 )   = refl
  ·ᵗʳ≡'·ᶻ (posᶻ      0 ) (posᶻ (suc b))   = refl
  ·ᵗʳ≡'·ᶻ (posᶻ (suc a)) (posᶻ      0 )   = refl
  ·ᵗʳ≡'·ᶻ (posᶻ (suc a)) (posᶻ (suc b))   = refl
  ·ᵗʳ≡'·ᶻ (posᶻ      0 ) (negsucᶻ   b )   = refl
  ·ᵗʳ≡'·ᶻ (posᶻ (suc a)) (negsucᶻ   b ) i = negsucᶻ (lemma1 a b i)
  ·ᵗʳ≡'·ᶻ (negsucᶻ   a ) (posᶻ      0 ) i = ℤ→Int (signed sneg (·ⁿ-nullifiesʳ a i))
  ·ᵗʳ≡'·ᶻ (negsucᶻ   a ) (posᶻ (suc b)) i = negsucᶻ (lemma1 a b i)
  ·ᵗʳ≡'·ᶻ (negsucᶻ   a ) (negsucᶻ   b )   = refl

  ·ᵗʳ≡·ᶻ : _·ᵗʳ_ ≡ _·ᶻ_
  ·ᵗʳ≡·ᶻ i a b = ·ᵗʳ≡'·ᶻ a b i

·≡·ᶻ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _·_ _·ᶻ_
·≡·ᶻ = J (λ _⋆_ _ → PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _·_ _⋆_) ·≡·ᵗʳ ·ᵗʳ≡·ᶻ

-- ·-assoc''''' : ∀ a b c → a · (b · c) ≡ (a · b) · c
-- ·-assoc''''' = transport γ ·-assoc where
--   γ : ((m n o : Z) → m · (n · o) ≡ (m · n) · o)
--     ≡ ((a b c : ℤ) → a · (b · c) ≡ (a · b) · c)
--   γ i = let _⋆_ = QuoInt·≡· i in (x y z : ℤ≡Int i) → x ⋆ (y ⋆ z) ≡ (x ⋆ y) ⋆ z

sucInt-preserves-ℤ→Int : ∀ a → sucInt (ℤ→Int a) ≡ ℤ→Int (sucℤ a)
sucInt-preserves-ℤ→Int (signed spos n) = refl
sucInt-preserves-ℤ→Int (signed sneg zero) = refl
sucInt-preserves-ℤ→Int (signed sneg (suc zero)) = refl
sucInt-preserves-ℤ→Int (signed sneg (suc (suc n))) = refl
sucInt-preserves-ℤ→Int (posneg i) = refl

predInt-preserves-ℤ→Int : ∀ a → predInt (ℤ→Int a) ≡ ℤ→Int (predℤ a)
predInt-preserves-ℤ→Int (signed spos zero) = refl
predInt-preserves-ℤ→Int (signed spos (suc n)) = refl
predInt-preserves-ℤ→Int (signed sneg zero) = refl
predInt-preserves-ℤ→Int (signed sneg (suc n)) = refl
predInt-preserves-ℤ→Int (posneg i) = refl

-sucℤ-sucℤ≡id : ∀ a → - sucℤ (- sucℤ a) ≡ a
-sucℤ-sucℤ≡id (signed spos n) = refl
-sucℤ-sucℤ≡id (signed sneg zero) = posneg
-sucℤ-sucℤ≡id (signed sneg (suc n)) = refl
-sucℤ-sucℤ≡id (posneg i) j = posneg (i ∧ j)

sucℤ-sucℤ-≡id : ∀ a → sucℤ (- sucℤ (- a)) ≡ a
sucℤ-sucℤ-≡id (signed spos zero) i = posneg (~ i)
sucℤ-sucℤ-≡id (signed spos (suc n)) = refl
sucℤ-sucℤ-≡id (signed sneg n) = refl
sucℤ-sucℤ-≡id (posneg i) j = posneg (i ∨ (~ j))

-sucℤ-sucℤ≡sucℤ-sucℤ- : ∀ a → - sucℤ (- sucℤ a) ≡ sucℤ (- sucℤ (- a))
-sucℤ-sucℤ≡sucℤ-sucℤ- a = -sucℤ-sucℤ≡id a ∙ sym (sucℤ-sucℤ-≡id a)

private
  _+ᵗʳ_ : Int → Int → Int
  _+ᵗʳ_ = transport (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _+_

  +≡+ᵗʳ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _+_ _+ᵗʳ_
  +≡+ᵗʳ i = transp (λ j → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j)) (~ i) _+_

  +ᵗʳ≡'+ᶻ : ∀ a b → a +ᵗʳ b ≡ a +ᶻ b
  +ᵗʳ≡'+ᶻ (posᶻ      0 ) (posᶻ      0 )   = refl
  +ᵗʳ≡'+ᶻ (posᶻ      0 ) (posᶻ (suc b))  i = sucInt (Int.+-comm (posᶻ b) 0 i)
  +ᵗʳ≡'+ᶻ (posᶻ (suc a)) (posᶻ      0 )  i = ℤ→Int (sucℤ (+-comm (pos a) 0 i))
  +ᵗʳ≡'+ᶻ (posᶻ (suc a)) (posᶻ (suc b))   =
    (posᶻ (suc a) +ᵗʳ posᶻ (suc b))  ≡⟨ sym (sucInt-preserves-ℤ→Int (signed spos a + signed spos (suc b))) ⟩
    sucInt (posᶻ a +ᵗʳ posᶻ (suc b)) ≡⟨ (λ i → sucInt $ (+ᵗʳ≡'+ᶻ (posᶻ a) (posᶻ (suc b)) ∙ sucInt+ (posᶻ a) (posᶻ b)) i) ⟩
    sucInt (posᶻ (suc a) +pos b)   ∎
  +ᵗʳ≡'+ᶻ (posᶻ      0 ) (negsucᶻ   b )   = sym (+negsuc-identityˡ b)
  +ᵗʳ≡'+ᶻ (posᶻ (suc a)) (negsucᶻ   b )   =
    (posᶻ (suc a) +ᵗʳ negsucᶻ b)  ≡⟨ sym $ sucInt-preserves-ℤ→Int (signed spos a + signed sneg (suc b)) ⟩
    sucInt (posᶻ a +ᵗʳ negsucᶻ b) ≡⟨ (λ i → sucInt $ +ᵗʳ≡'+ᶻ (posᶻ a) (negsucᶻ b) i) ⟩
    sucInt (posᶻ a +ᶻ  negsucᶻ b) ≡⟨ sucInt+ (posᶻ a) (negsucᶻ b) ⟩
    (posᶻ (suc a) +negsuc b)    ∎
  +ᵗʳ≡'+ᶻ (negsucᶻ   a ) (posᶻ      0 )   i = ℤ→Int $ -_ $  sucℤ $ -_ $ +-comm (signed sneg a) (pos 0) i
  +ᵗʳ≡'+ᶻ (negsucᶻ   a ) (posᶻ (suc b))   =
    (negsucᶻ a +ᵗʳ posᶻ (suc b))  ≡⟨ (λ i → ℤ→Int $ - sucℤ (- sucℤ-+ʳ (signed sneg a) (signed spos b) (~ i))) ⟩
    ℤ→Int (- sucℤ (- sucℤ (signed sneg a + signed spos b))) ≡⟨ (λ i → ℤ→Int $ -sucℤ-sucℤ≡sucℤ-sucℤ- (signed sneg a + signed spos b) i) ⟩
    ℤ→Int (sucℤ (- sucℤ (- (signed sneg a + signed spos b)))) ≡⟨ sym $ sucInt-preserves-ℤ→Int (- sucℤ (- (signed sneg a + signed spos b))) ⟩
    sucInt (negsucᶻ a +ᵗʳ posᶻ b) ≡⟨ (λ i → sucInt $ +ᵗʳ≡'+ᶻ (negsucᶻ a) (posᶻ b) i) ⟩
    sucInt (negsucᶻ a +pos b)   ∎
  +ᵗʳ≡'+ᶻ (negsucᶻ zero) (negsucᶻ b) = sym $ negsuc+negsuc≡+ⁿ 0 b
  +ᵗʳ≡'+ᶻ (negsucᶻ (suc a)) (negsucᶻ b) =
   (negsucᶻ (suc a) +ᵗʳ negsucᶻ b)   ≡⟨ sym $ predInt-preserves-ℤ→Int (- sucℤ (- (signed sneg a + signed sneg (suc b)))) ⟩
   predInt (negsucᶻ a +ᵗʳ negsucᶻ b) ≡⟨ (λ i → predInt $ +ᵗʳ≡'+ᶻ (negsucᶻ a) (negsucᶻ b) i) ⟩
   predInt (negsucᶻ a +ᶻ  negsucᶻ b) ≡⟨ predInt+ (negsucᶻ a) (negsucᶻ b) ⟩
   (negsucᶻ (suc a) +negsuc b)     ∎

  +ᵗʳ≡+ᶻ : _+ᵗʳ_ ≡ _+ᶻ_
  +ᵗʳ≡+ᶻ i a b = +ᵗʳ≡'+ᶻ a b i

+≡+ᶻ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _+_ _+ᶻ_
+≡+ᶻ = J (λ _+ᵗʳ_ _ → PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) _+_ _+ᵗʳ_) +≡+ᵗʳ +ᵗʳ≡+ᶻ

private
  -ᵗʳ_ : Int → Int
  -ᵗʳ_ = transport (λ i → (ℤ≡Int i → ℤ≡Int i)) -_

  -≡-ᵗʳ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i)) -_ -ᵗʳ_
  -≡-ᵗʳ i = transp (λ j → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j)) (~ i) -_

  -ᵗʳ≡'-ᶻ : ∀ a → -ᵗʳ a ≡ -ᶻ a
  -ᵗʳ≡'-ᶻ (posᶻ zero) = refl
  -ᵗʳ≡'-ᶻ (posᶻ (suc n)) = refl
  -ᵗʳ≡'-ᶻ (negsucᶻ n) = refl

  -ᵗʳ≡-ᶻ : (-ᵗʳ_) ≡ (-ᶻ_)
  -ᵗʳ≡-ᶻ i a = -ᵗʳ≡'-ᶻ a i

-≡-ᶻ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i)) (-_) (-ᶻ_)
-≡-ᶻ = J (λ -ᵗʳ_ _ → PathP (λ i → (ℤ≡Int i → ℤ≡Int i)) -_ -ᵗʳ_) -≡-ᵗʳ -ᵗʳ≡-ᶻ

min : ℤ → ℤ → ℤ
min x y with sign x | sign y
... | spos | spos = pos (minⁿ (abs x) (abs y))
... | spos | sneg = y
... | sneg | spos = x
... | sneg | sneg = neg (maxⁿ (abs x) (abs y))

max : ℤ → ℤ → ℤ
max x y with sign x | sign y
... | spos | spos = pos (maxⁿ (abs x) (abs y))
... | spos | sneg = x
... | sneg | spos = y
... | sneg | sneg = neg (minⁿ (abs x) (abs y))

private
  minᵗʳ : Int → Int → Int
  minᵗʳ = transport (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) min

  maxᵗʳ : Int → Int → Int
  maxᵗʳ = transport (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) max

  min≡minᵗʳ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) min minᵗʳ
  min≡minᵗʳ i = transp (λ j → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j)) (~ i) min

  max≡maxᵗʳ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) max maxᵗʳ
  max≡maxᵗʳ i = transp (λ j → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j)) (~ i) max

  minᵗʳ≡'minᶻ : ∀ a b → minᵗʳ a b ≡ minᶻ a b
  minᵗʳ≡'minᶻ (posᶻ      0 ) (posᶻ      0 ) = refl
  minᵗʳ≡'minᶻ (posᶻ      0 ) (posᶻ (suc b)) = refl
  minᵗʳ≡'minᶻ (posᶻ (suc a)) (posᶻ      0 ) = refl
  minᵗʳ≡'minᶻ (posᶻ (suc a)) (posᶻ (suc b)) = refl
  minᵗʳ≡'minᶻ (posᶻ      0 ) (negsucᶻ   b ) = refl
  minᵗʳ≡'minᶻ (posᶻ (suc a)) (negsucᶻ   b ) = refl
  minᵗʳ≡'minᶻ (negsucᶻ   a ) (posᶻ      0 ) = refl
  minᵗʳ≡'minᶻ (negsucᶻ   a ) (posᶻ (suc b)) = refl
  minᵗʳ≡'minᶻ (negsucᶻ   a ) (negsucᶻ   b ) = refl

  maxᵗʳ≡'maxᶻ : ∀ a b → maxᵗʳ a b ≡ maxᶻ a b
  maxᵗʳ≡'maxᶻ (posᶻ      0 ) (posᶻ      0 ) = refl
  maxᵗʳ≡'maxᶻ (posᶻ      0 ) (posᶻ (suc b)) = refl
  maxᵗʳ≡'maxᶻ (posᶻ (suc a)) (posᶻ      0 ) = refl
  maxᵗʳ≡'maxᶻ (posᶻ (suc a)) (posᶻ (suc b)) = refl
  maxᵗʳ≡'maxᶻ (posᶻ      0 ) (negsucᶻ   b ) = refl
  maxᵗʳ≡'maxᶻ (posᶻ (suc a)) (negsucᶻ   b ) = refl
  maxᵗʳ≡'maxᶻ (negsucᶻ   a ) (posᶻ      0 ) = refl
  maxᵗʳ≡'maxᶻ (negsucᶻ   a ) (posᶻ (suc b)) = refl
  maxᵗʳ≡'maxᶻ (negsucᶻ   a ) (negsucᶻ   b ) = refl

  minᵗʳ≡minᶻ : minᵗʳ ≡ minᶻ
  minᵗʳ≡minᶻ i a b = minᵗʳ≡'minᶻ a b i

  maxᵗʳ≡maxᶻ : maxᵗʳ ≡ maxᶻ
  maxᵗʳ≡maxᶻ i a b = maxᵗʳ≡'maxᶻ a b i

min≡min : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) min minᶻ
min≡min = J (λ minᵗʳ _ → PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) min minᵗʳ) min≡minᵗʳ minᵗʳ≡minᶻ

max≡max : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) max maxᶻ
max≡max = J (λ maxᵗʳ _ → PathP (λ i → (ℤ≡Int i → ℤ≡Int i → ℤ≡Int i)) max maxᵗʳ) max≡maxᵗʳ maxᵗʳ≡maxᶻ

infixl 4 _<_
_<_ : ∀(x y : ℤ) → hProp ℓ-zero
x < y with sign x | sign y
... | spos | spos = abs x <ⁿ abs y
... | spos | sneg = ⊥
... | sneg | spos = ⊤
... | sneg | sneg = abs y <ⁿ abs x

private

  _<ᵗʳ_ : Int → Int → hProp ℓ-zero
  _<ᵗʳ_ = transport (λ i → (ℤ≡Int i → ℤ≡Int i → hProp ℓ-zero)) _<_

  <≡<ᵗʳ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → hProp ℓ-zero)) _<_ _<ᵗʳ_
  <≡<ᵗʳ i = transp (λ j → ℤ≡Int (i ∧ j) → ℤ≡Int (i ∧ j) → hProp ℓ-zero) (~ i) _<_

  <ᵗʳ⇔<ᶻ : ∀ a b → [ (a <ᵗʳ b) ⇔ (a <ᶻ b) ]
  <ᵗʳ⇔<ᶻ (posᶻ      0 ) (posᶻ      0 ) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (posᶻ      0 ) (posᶻ (suc b)) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (posᶻ (suc a)) (posᶻ      0 ) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (posᶻ (suc a)) (posᶻ (suc b)) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (posᶻ      0 ) (negsucᶻ   b ) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (posᶻ (suc a)) (negsucᶻ   b ) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (negsucᶻ   a ) (posᶻ      0 ) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (negsucᶻ   a ) (posᶻ (suc b)) .fst pᵗʳ = pᵗʳ
  <ᵗʳ⇔<ᶻ (negsucᶻ   a ) (negsucᶻ   b ) .fst pᵗʳ = sucⁿ-creates-<ⁿ b a .snd pᵗʳ
  <ᵗʳ⇔<ᶻ (posᶻ      0 ) (posᶻ      0 ) .snd p  = p
  <ᵗʳ⇔<ᶻ (posᶻ      0 ) (posᶻ (suc b)) .snd p  = p
  <ᵗʳ⇔<ᶻ (posᶻ (suc a)) (posᶻ      0 ) .snd p  = p
  <ᵗʳ⇔<ᶻ (posᶻ (suc a)) (posᶻ (suc b)) .snd p  = p
  <ᵗʳ⇔<ᶻ (negsucᶻ   a ) (posᶻ      0 ) .snd p  = p
  <ᵗʳ⇔<ᶻ (negsucᶻ   a ) (posᶻ (suc b)) .snd p  = p
  <ᵗʳ⇔<ᶻ (negsucᶻ   a ) (negsucᶻ   b ) .snd p  = sucⁿ-creates-<ⁿ b a .fst p

  <ᵗʳ≡<ᶻ : _<ᵗʳ_ ≡ _<ᶻ_
  <ᵗʳ≡<ᶻ i a b = ⇔toPath {P = a <ᵗʳ b} {Q = a <ᶻ b} (<ᵗʳ⇔<ᶻ a b .fst) (<ᵗʳ⇔<ᶻ a b .snd) i

<≡<ᶻ : PathP (λ i → (ℤ≡Int i → ℤ≡Int i → hProp ℓ-zero)) _<_ _<ᶻ_
<≡<ᶻ = J (λ _<ᵗʳ_ _ → PathP (λ i → (ℤ≡Int i → ℤ≡Int i → hProp ℓ-zero)) _<_ _<ᵗʳ_) <≡<ᵗʳ <ᵗʳ≡<ᶻ

is-LinearlyOrderedCommRing : [ isLinearlyOrderedCommRing 0 1 _+_ _·_ -_ _<_ min max ]
is-LinearlyOrderedCommRing = transport γ is-LinearlyOrderedCommRingᶻ where
  γ : ([ isLinearlyOrderedCommRing 0 1 _+ᶻ_ _·ᶻ_ (-ᶻ_) _<ᶻ_ minᶻ maxᶻ ])
    ≡ [ isLinearlyOrderedCommRing 0 1 _+_ _·_ -_ _<_ min max ]
  γ i = [ isLinearlyOrderedCommRing 0ⁱ 1ⁱ _+ⁱ_ _·ⁱ_ -ⁱ_ _<ⁱ_ minⁱ maxⁱ ] where
    0ⁱ = transport (λ j → ℤ≡Int (~ i ∧ j)) 0
    1ⁱ = transport (λ j → ℤ≡Int (~ i ∧ j)) 1
    _+ⁱ_ = +≡+ᶻ (~ i)
    _·ⁱ_ = ·≡·ᶻ (~ i)
    -ⁱ_  = -≡-ᶻ (~ i)
    _<ⁱ_ = <≡<ᶻ (~ i)
    minⁱ = min≡min (~ i)
    maxⁱ = max≡max (~ i)

bundle : LinearlyOrderedCommRing {ℓ-zero} {ℓ-zero}
bundle .LinearlyOrderedCommRing.Carrier                    = ℤ
bundle .LinearlyOrderedCommRing.0f                         = 0
bundle .LinearlyOrderedCommRing.1f                         = 1
bundle .LinearlyOrderedCommRing._+_                        = _+_
bundle .LinearlyOrderedCommRing._·_                        = _·_
bundle .LinearlyOrderedCommRing.-_                         = -_
bundle .LinearlyOrderedCommRing.min                        = min
bundle .LinearlyOrderedCommRing.max                        = max
bundle .LinearlyOrderedCommRing._<_                        = _<_
bundle .LinearlyOrderedCommRing.is-LinearlyOrderedCommRing = is-LinearlyOrderedCommRing

·-reflects-< : (x y z : ℤ) → [ 0 < z ] → [ (x · z) < (y · z) ] → [ x < y ]
·-reflects-< = transport γ ·ᶻ-reflects-<ᶻ where
  γ : ((x y z : Int) → [ 0 <ᶻ z ] → [  x ·ᶻ z  <ᶻ  y ·ᶻ z  ] → [ x <ᶻ y ])
    ≡ ((x y z :   ℤ) → [ 0 < z ] → [ (x · z) < (y · z) ] → [ x < y ])
  γ i = let _·'_ = ·≡·ᶻ (~ i); _<'_ = <≡<ᶻ (~ i); 0ⁱ = transport (λ j → ℤ≡Int (~ i ∧ j)) 0 in
      ((x y z :    ℤ≡Int (~ i)) → [ 0ⁱ <' z ] → [ (x ·' z) <' (y ·' z) ] → [ x <' y ])


{-# OPTIONS --safe #-}

open import Definition.Typed.EqualityRelation

module Definition.LogicalRelation.Substitution.MaybeEmbed {{eqrel : EqRelSet}} where
open EqRelSet {{...}}

open import Definition.Untyped
open import Definition.LogicalRelation
open import Definition.LogicalRelation.Irrelevance
open import Definition.LogicalRelation.Properties
open import Definition.LogicalRelation.Substitution

open import Tools.Product

-- Any level can be embedded into the highest level (validity variant).
maybeEmbᵛ : ∀ {l A r Γ}
            ([Γ] : ⊩ᵛ Γ)
          → Γ ⊩ᵛ⟨ l ⟩ A ^ r / [Γ]
          → Γ ⊩ᵛ⟨ ∞ ⟩ A ^ r / [Γ]
maybeEmbᵛ {ι ⁰} [Γ] [A] ⊢Δ [σ] =
  let [σA]  = proj₁ ([A] ⊢Δ [σ])
      [σA]′ = maybeEmb (proj₁ ([A] ⊢Δ [σ]))
  in  [σA]′
  ,   (λ [σ′] [σ≡σ′] → irrelevanceEq [σA] [σA]′ (proj₂ ([A] ⊢Δ [σ]) [σ′] [σ≡σ′]))
maybeEmbᵛ {ι ¹} [Γ] [A] ⊢Δ [σ] =
  let [σA]  = proj₁ ([A] ⊢Δ [σ])
      [σA]′ = maybeEmb (proj₁ ([A] ⊢Δ [σ]))
  in  [σA]′
  ,   (λ [σ′] [σ≡σ′] → irrelevanceEq [σA] [σA]′ (proj₂ ([A] ⊢Δ [σ]) [σ′] [σ≡σ′]))
maybeEmbᵛ {∞} [Γ] [A] ⊢Δ [σ] = [A] ⊢Δ [σ]

maybeEmbTermᵛ : ∀ {l A t r Γ}
         → ([Γ] : ⊩ᵛ Γ)
         → ([A] : Γ ⊩ᵛ⟨ l ⟩ A ^ r / [Γ])
         → Γ ⊩ᵛ⟨ l ⟩ t ∷ A ^ r / [Γ] / [A]
         → Γ ⊩ᵛ⟨ ∞ ⟩ t ∷ A ^ r / [Γ] / maybeEmbᵛ {A = A} [Γ] [A]
maybeEmbTermᵛ {ι ⁰} [Γ] [A] [t] = [t]
maybeEmbTermᵛ {ι ¹} [Γ] [A] [t] = [t]
maybeEmbTermᵛ {∞} [Γ] [A] [t] = [t]

-- The lowest level can be embedded in any level (validity variant).
maybeEmbₛ′ : ∀ {l A r Γ}
             ([Γ] : ⊩ᵛ Γ)
           → Γ ⊩ᵛ⟨ ι ⁰ ⟩ A ^ r / [Γ]
           → Γ ⊩ᵛ⟨ l ⟩ A ^ r / [Γ]
maybeEmbₛ′ {ι ⁰} [Γ] [A] = [A]
maybeEmbₛ′ {ι ¹} [Γ] [A] ⊢Δ [σ] =
  let [σA]  = proj₁ ([A] ⊢Δ [σ])
      [σA]′ = maybeEmb′ (<is≤ 0<1) (proj₁ ([A] ⊢Δ [σ]))
  in  [σA]′
  ,   (λ [σ′] [σ≡σ′] → irrelevanceEq [σA] [σA]′ (proj₂ ([A] ⊢Δ [σ]) [σ′] [σ≡σ′]))
maybeEmbₛ′ {∞} [Γ] [A] ⊢Δ [σ] =
  let [σA]  = proj₁ ([A] ⊢Δ [σ])
      [σA]′ = maybeEmb (proj₁ ([A] ⊢Δ [σ]))
  in  [σA]′
  ,   (λ [σ′] [σ≡σ′] → irrelevanceEq [σA] [σA]′ (proj₂ ([A] ⊢Δ [σ]) [σ′] [σ≡σ′]))

maybeEmbEqTermᵛ : ∀ {l A t u r Γ}
         → ([Γ] : ⊩ᵛ Γ)
         → ([A] : Γ ⊩ᵛ⟨ l ⟩ A ^ r / [Γ] )
         → Γ ⊩ᵛ⟨ l ⟩ t ≡ u ∷ A ^ r / [Γ] / [A]
         → Γ ⊩ᵛ⟨ ∞ ⟩ t ≡ u ∷ A ^ r / [Γ] / maybeEmbᵛ {A = A} [Γ] [A]
maybeEmbEqTermᵛ {ι ⁰} [Γ] [A] [t≡u] = [t≡u]
maybeEmbEqTermᵛ {ι ¹} [Γ] [A] [t≡u] = [t≡u]
maybeEmbEqTermᵛ {∞} [Γ] [A] [t≡u] = [t≡u]


module FFI.Data.Either where

{-# FOREIGN GHC import qualified Data.Either #-}

data Either (A B : Set) : Set where
  Left : A → Either A B
  Right : B → Either A B
{-# COMPILE GHC Either = data Data.Either.Either (Data.Either.Left|Data.Either.Right) #-}

mapLeft : ∀ {A B C} → (A → B) → (Either A C) → (Either B C)
mapLeft f (Left x) = Left (f x)
mapLeft f (Right x) = Right x

mapRight : ∀ {A B C} → (B → C) → (Either A B) → (Either A C)
mapRight f (Left x) = Left x
mapRight f (Right x) = Right (f x)


{-# OPTIONS --without-K --safe #-}

open import Definition.Typed.EqualityRelation

module Definition.LogicalRelation.Substitution {{eqrel : EqRelSet}} where

open import Definition.Untyped hiding (_∷_)
open import Definition.Typed
open import Definition.LogicalRelation

open import Tools.Nat
open import Tools.Product
open import Tools.Unit

private
  variable
    k ℓ m n l : Nat
    Γ : Con Term n

-- The validity judgements:
-- We consider expressions that satisfy these judgments valid

mutual
  -- Validity of contexts
  data ⊩ᵛ_ : Con Term n → Set where
    ε : ⊩ᵛ ε
    _∙_ : ∀ {A l} ([Γ] : ⊩ᵛ Γ) → Γ ⊩ᵛ⟨ l ⟩ A / [Γ]
        → ⊩ᵛ Γ ∙ A

  -- Validity of types
  _⊩ᵛ⟨_⟩_/_ : {n : Nat} (Γ : Con Term n) (l : TypeLevel) (A : Term n) → ⊩ᵛ Γ → Set
  _⊩ᵛ⟨_⟩_/_ {n} Γ l A [Γ] =
    ∀ {k : Nat} {Δ : Con Term k} {σ : Subst k n} (⊢Δ : ⊢ Δ) ([σ] : Δ ⊩ˢ σ ∷ Γ / [Γ] / ⊢Δ)
    → Σ (Δ ⊩⟨ l ⟩ subst σ A) (λ [Aσ]
      → ∀ {σ′} ([σ′] : Δ ⊩ˢ σ′ ∷ Γ / [Γ] / ⊢Δ)
        ([σ≡σ′] : Δ ⊩ˢ σ ≡ σ′ ∷ Γ / [Γ] / ⊢Δ / [σ])
      → Δ ⊩⟨ l ⟩ subst σ A ≡ subst σ′ A / [Aσ])

  -- Logical relation for substitutions from a valid context
  _⊩ˢ_∷_/_/_ : (Δ : Con Term n) (σ : Subst n m) (Γ : Con Term m) ([Γ] : ⊩ᵛ Γ) (⊢Δ : ⊢ Δ)
             → Set
  Δ ⊩ˢ σ ∷ .ε        / ε  / ⊢Δ                = ⊤
  Δ ⊩ˢ σ ∷ .(Γ ∙ A) / (_∙_ {Γ = Γ} {A} {l} [Γ] [A]) / ⊢Δ =
    Σ (Δ ⊩ˢ tail σ ∷ Γ / [Γ] / ⊢Δ) λ [tailσ] →
      (Δ ⊩⟨ l ⟩ head σ ∷ subst (tail σ) A / proj₁ ([A] ⊢Δ [tailσ]))

  -- Logical relation for equality of substitutions from a valid context
  _⊩ˢ_≡_∷_/_/_/_ : (Δ : Con Term n) (σ σ′ : Subst n m) (Γ : Con Term m) ([Γ] : ⊩ᵛ Γ)
                    (⊢Δ : ⊢ Δ) ([σ] : Δ ⊩ˢ σ ∷ Γ / [Γ] / ⊢Δ) → Set
  --Δ ⊩ˢ σ ≡ σ′ ∷ Γ / x / y / z = {!   !}
  Δ ⊩ˢ σ ≡ σ′ ∷ .ε       / ε       / ⊢Δ              / [σ] = ⊤
  Δ ⊩ˢ σ ≡ σ′ ∷ .(Γ ∙ A) / (_∙_ {Γ = Γ} {A} {l} [Γ] [A]) / ⊢Δ / [σ] =
    (Δ ⊩ˢ tail σ ≡ tail σ′ ∷ Γ / [Γ] / ⊢Δ / proj₁ [σ]) ×
    (Δ ⊩⟨ l ⟩ head σ ≡ head σ′ ∷ subst (tail σ) A / proj₁ ([A] ⊢Δ (proj₁ [σ])))

-- Validity of terms
_⊩ᵛ⟨_⟩_∷_/_/_ : (Γ : Con Term n) (l : TypeLevel) (t A : Term n) ([Γ] : ⊩ᵛ Γ)
                 ([A] : Γ ⊩ᵛ⟨ l ⟩ A / [Γ]) → Set
Γ ⊩ᵛ⟨ l ⟩ t ∷ A / [Γ] / [A] =
  ∀ {k} {Δ : Con Term k} {σ} (⊢Δ : ⊢ Δ) ([σ] : Δ ⊩ˢ σ ∷ Γ / [Γ] / ⊢Δ) →
  Σ (Δ ⊩⟨ l ⟩ subst σ t ∷ subst σ A / proj₁ ([A] ⊢Δ [σ])) λ [tσ] →
  ∀ {σ′} → Δ ⊩ˢ σ′ ∷ Γ / [Γ] / ⊢Δ → Δ ⊩ˢ σ ≡ σ′ ∷ Γ / [Γ] / ⊢Δ / [σ]
    → Δ ⊩⟨ l ⟩ subst σ t ≡ subst σ′ t ∷ subst σ A / proj₁ ([A] ⊢Δ [σ])

-- Validity of type equality
_⊩ᵛ⟨_⟩_≡_/_/_ : (Γ : Con Term n) (l : TypeLevel) (A B : Term n) ([Γ] : ⊩ᵛ Γ)
                ([A] : Γ ⊩ᵛ⟨ l ⟩ A / [Γ]) → Set
Γ ⊩ᵛ⟨ l ⟩ A ≡ B / [Γ] / [A] =
  ∀ {k} {Δ : Con Term k} {σ} (⊢Δ : ⊢ Δ) ([σ] : Δ ⊩ˢ σ ∷ Γ / [Γ] / ⊢Δ)
  → Δ ⊩⟨ l ⟩ subst σ A ≡ subst σ B / proj₁ ([A] ⊢Δ [σ])

-- Validity of term equality
_⊩ᵛ⟨_⟩_≡_∷_/_/_ : (Γ : Con Term n) (l : TypeLevel) (t u A : Term n) ([Γ] : ⊩ᵛ Γ)
                    ([A] : Γ ⊩ᵛ⟨ l ⟩ A / [Γ]) → Set
Γ ⊩ᵛ⟨ l ⟩ t ≡ u ∷ A / [Γ] / [A] =
  ∀ {k} {Δ : Con Term k} {σ} → (⊢Δ : ⊢ Δ) ([σ] : Δ ⊩ˢ σ ∷ Γ / [Γ] / ⊢Δ)
          → Δ ⊩⟨ l ⟩ subst σ t ≡ subst σ u ∷ subst σ A / proj₁ ([A] ⊢Δ [σ])

-- Valid term equality with validity of its type and terms
record [_⊩ᵛ⟨_⟩_≡_∷_/_] (Γ : Con Term n) (l : TypeLevel)
                       (t u A : Term n) ([Γ] : ⊩ᵛ Γ) : Set where
  constructor modelsTermEq
  field
    [A]   : Γ ⊩ᵛ⟨ l ⟩ A / [Γ]
    [t]   : Γ ⊩ᵛ⟨ l ⟩ t ∷ A / [Γ] / [A]
    [u]   : Γ ⊩ᵛ⟨ l ⟩ u ∷ A / [Γ] / [A]
    [t≡u] : Γ ⊩ᵛ⟨ l ⟩ t ≡ u ∷ A / [Γ] / [A]

-- Validity of reduction of terms
_⊩ᵛ_⇒_∷_/_ : (Γ : Con Term n) (t u A : Term n) ([Γ] : ⊩ᵛ Γ) → Set
Γ ⊩ᵛ t ⇒ u ∷ A / [Γ] = ∀ {k} {Δ : Con Term k} {σ} (⊢Δ : ⊢ Δ) ([σ] : Δ ⊩ˢ σ ∷ Γ / [Γ] / ⊢Δ)
                       → Δ ⊢ subst σ t ⇒ subst σ u ∷ subst σ A


{-# OPTIONS --without-K --safe #-}

open import Definition.Typed.EqualityRelation

module Definition.LogicalRelation.Substitution.Introductions.Empty {{eqrel : EqRelSet}} where
open EqRelSet {{...}}

open import Definition.Untyped
open import Definition.Typed
open import Definition.Typed.Properties
open import Definition.LogicalRelation
open import Definition.LogicalRelation.Properties
open import Definition.LogicalRelation.Substitution
open import Definition.LogicalRelation.Substitution.Introductions.Universe

open import Tools.Unit
open import Tools.Product

-- Validity of the Empty type.
Emptyᵛ : ∀ {Γ l} ([Γ] : ⊩ᵛ Γ) → Γ ⊩ᵛ⟨ l ⟩ Empty / [Γ]
Emptyᵛ [Γ] ⊢Δ [σ] = Emptyᵣ (idRed:*: (Emptyⱼ ⊢Δ)) , λ _ x₂ → id (Emptyⱼ ⊢Δ)

-- Validity of the Empty type as a term.
Emptyᵗᵛ : ∀ {Γ} ([Γ] : ⊩ᵛ Γ)
    → Γ ⊩ᵛ⟨ ¹ ⟩ Empty ∷ U / [Γ] / Uᵛ [Γ]
Emptyᵗᵛ [Γ] ⊢Δ [σ] = let ⊢Empty  = Emptyⱼ ⊢Δ
                         [Empty] = Emptyᵣ (idRed:*: (Emptyⱼ ⊢Δ))
                 in  Uₜ Empty (idRedTerm:*: ⊢Empty) Emptyₙ (≅ₜ-Emptyrefl ⊢Δ) [Empty]
                 ,   (λ x x₁ → Uₜ₌ Empty Empty (idRedTerm:*: ⊢Empty) (idRedTerm:*: ⊢Empty) Emptyₙ Emptyₙ
                                   (≅ₜ-Emptyrefl ⊢Δ) [Empty] [Empty] (id (Emptyⱼ ⊢Δ)))


{-# OPTIONS --without-K --safe #-}

module Categories.Category.Finite.Fin.Instance.Span where

open import Data.Nat using (ℕ)
open import Data.Fin
open import Data.Fin.Patterns
open import Relation.Binary.PropositionalEquality using (_≡_ ; refl)

open import Categories.Category.Finite.Fin
open import Categories.Category
open import Categories.Functor using (Functor; _∘F_) renaming (id to idF)
open import Categories.NaturalTransformation using (ntHelper)
open import Categories.NaturalTransformation.NaturalIsomorphism using (_≃_)
open import Categories.Adjoint.Equivalence using (_⊣⊢_; ⊣Equivalence; withZig)
import Categories.Morphism as Mor
import Categories.Category.Instance.Span as Sp

private
  variable
    a b c d : Fin 3

-- The diagram is the following:
--
-- 1 <------- 0 -------> 2
--
SpanShape : FinCatShape
SpanShape = record
  { size     = 3
  ; ∣_⇒_∣    = morph
  ; hasShape = record
    { id        = id
    ; _∘_       = _∘_
    ; assoc     = assoc
    ; identityˡ = identityˡ
    ; identityʳ = identityʳ
    }
  }
  where morph : Fin 3 → Fin 3 → ℕ
        morph 0F 0F = 1
        morph 0F 1F = 1
        morph 0F 2F = 1
        morph 1F 1F = 1
        morph 2F 2F = 1
        morph _ _   = 0

        id : Fin (morph a a)
        id {0F} = 0F
        id {1F} = 0F
        id {2F} = 0F

        _∘_ : ∀ {a b c} → Fin (morph b c) → Fin (morph a b) → Fin (morph a c)
        _∘_ {0F} {0F} {0F} 0F 0F = 0F
        _∘_ {0F} {0F} {1F} 0F 0F = 0F
        _∘_ {0F} {0F} {2F} 0F 0F = 0F
        _∘_ {0F} {1F} {1F} 0F 0F = 0F
        _∘_ {0F} {2F} {2F} 0F 0F = 0F
        _∘_ {1F} {1F} {1F} 0F 0F = 0F
        _∘_ {2F} {2F} {2F} 0F 0F = 0F

        assoc : ∀ {f : Fin (morph a b)} {g : Fin (morph b c)} {h : Fin (morph c d)} →
                  ((h ∘ g) ∘ f) ≡ (h ∘ (g ∘ f))
        assoc {0F} {0F} {0F} {0F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {0F} {1F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {0F} {2F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {1F} {1F} {0F} {0F} {0F} = refl
        assoc {0F} {0F} {2F} {2F} {0F} {0F} {0F} = refl
        assoc {0F} {1F} {1F} {1F} {0F} {0F} {0F} = refl
        assoc {0F} {2F} {2F} {2F} {0F} {0F} {0F} = refl
        assoc {1F} {1F} {1F} {1F} {0F} {0F} {0F} = refl
        assoc {2F} {2F} {2F} {2F} {0F} {0F} {0F} = refl

        identityˡ : ∀ {f : Fin (morph a b)} → (id ∘ f) ≡ f
        identityˡ {0F} {0F} {0F} = refl
        identityˡ {0F} {1F} {0F} = refl
        identityˡ {0F} {2F} {0F} = refl
        identityˡ {1F} {1F} {0F} = refl
        identityˡ {2F} {2F} {0F} = refl

        identityʳ : ∀ {f : Fin (morph a b)} → (f ∘ id) ≡ f
        identityʳ {0F} {0F} {0F} = refl
        identityʳ {0F} {1F} {0F} = refl
        identityʳ {0F} {2F} {0F} = refl
        identityʳ {1F} {1F} {0F} = refl
        identityʳ {2F} {2F} {0F} = refl

Span : Category _ _ _
Span = FinCategory SpanShape

module Span = Category Span

open FinCatShape SpanShape

SpanToF : Functor Span Sp.Span
SpanToF = record
  { F₀           = F₀
  ; F₁           = F₁
  ; identity     = identity
  ; homomorphism = homomorphism
  ; F-resp-≈     = F-resp-≈
  }
  where F₀ : Fin 3 → Sp.SpanObj
        F₀ 0F = Sp.center
        F₀ 1F = Sp.left
        F₀ 2F = Sp.right

        F₁ : Fin ∣ a ⇒ b ∣ → Sp.SpanArr (F₀ a) (F₀ b)
        F₁ {0F} {0F} 0F = Sp.span-id
        F₁ {0F} {1F} 0F = Sp.span-arrˡ
        F₁ {0F} {2F} 0F = Sp.span-arrʳ
        F₁ {1F} {1F} 0F = Sp.span-id
        F₁ {2F} {2F} 0F = Sp.span-id

        identity : F₁ (id {a}) ≡ Sp.span-id
        identity {0F} = refl
        identity {1F} = refl
        identity {2F} = refl

        homomorphism : ∀ {f : Fin ∣ a ⇒ b ∣} {g : Fin ∣ b ⇒ c ∣} →
                         F₁ (g ∘ f) ≡ Sp.span-compose (F₁ g) (F₁ f)
        homomorphism {0F} {0F} {0F} {0F} {0F} = refl
        homomorphism {0F} {0F} {1F} {0F} {0F} = refl
        homomorphism {0F} {0F} {2F} {0F} {0F} = refl
        homomorphism {0F} {1F} {1F} {0F} {0F} = refl
        homomorphism {0F} {2F} {2F} {0F} {0F} = refl
        homomorphism {1F} {1F} {1F} {0F} {0F} = refl
        homomorphism {2F} {2F} {2F} {0F} {0F} = refl

        F-resp-≈ : ∀ {f g : Fin ∣ a ⇒ b ∣} → f ≡ g → F₁ f ≡ F₁ g
        F-resp-≈ {0F} {0F} {0F} {0F} _ = refl
        F-resp-≈ {0F} {1F} {0F} {0F} _ = refl
        F-resp-≈ {0F} {2F} {0F} {0F} _ = refl
        F-resp-≈ {1F} {1F} {0F} {0F} _ = refl
        F-resp-≈ {2F} {2F} {0F} {0F} _ = refl

module SpanToF = Functor SpanToF

SpanFromF : Functor Sp.Span Span
SpanFromF = record
  { F₀           = F₀
  ; F₁           = F₁
  ; identity     = identity
  ; homomorphism = homomorphism
  ; F-resp-≈     = F-resp-≈
  }
  where F₀ : Sp.SpanObj → Fin 3
        F₀ Sp.center = 0F
        F₀ Sp.left   = 1F
        F₀ Sp.right  = 2F

        F₁ : ∀ {A B} → Sp.Span [ A , B ] → Span [ F₀ A , F₀ B ]
        F₁ {Sp.center} Sp.span-id = 0F
        F₁ {Sp.left} Sp.span-id   = 0F
        F₁ {Sp.right} Sp.span-id  = 0F
        F₁ Sp.span-arrˡ           = 0F
        F₁ Sp.span-arrʳ           = 0F

        identity : ∀ {A} → F₁ (Category.id Sp.Span {A}) ≡ id
        identity {Sp.center} = refl
        identity {Sp.left}   = refl
        identity {Sp.right}  = refl

        homomorphism : ∀ {X Y Z} {f : Sp.Span [ X , Y ]} {g : Sp.Span [ Y , Z ]} →
                       F₁ (Sp.Span [ g ∘ f ]) ≡ F₁ g ∘ F₁ f
        homomorphism {Sp.center} {_} {_} {Sp.span-id} {Sp.span-id} = refl
        homomorphism {Sp.left} {_} {_} {Sp.span-id} {Sp.span-id}   = refl
        homomorphism {Sp.right} {_} {_} {Sp.span-id} {Sp.span-id}  = refl
        homomorphism {_} {_} {_} {Sp.span-id} {Sp.span-arrˡ}       = refl
        homomorphism {_} {_} {_} {Sp.span-id} {Sp.span-arrʳ}       = refl
        homomorphism {_} {_} {_} {Sp.span-arrˡ} {Sp.span-id}       = refl
        homomorphism {_} {_} {_} {Sp.span-arrʳ} {Sp.span-id}       = refl

        F-resp-≈ : ∀ {A B} {f g : Sp.Span [ A , B ]} → f ≡ g → F₁ f ≡ F₁ g
        F-resp-≈ {Sp.center} {_} {Sp.span-id} {Sp.span-id} _              = refl
        F-resp-≈ {Sp.left} {_} {Sp.span-id} {Sp.span-id} _                = refl
        F-resp-≈ {Sp.right} {_} {Sp.span-id} {Sp.span-id} _               = refl
        F-resp-≈ {.Sp.center} {.Sp.left} {Sp.span-arrˡ} {Sp.span-arrˡ} _  = refl
        F-resp-≈ {.Sp.center} {.Sp.right} {Sp.span-arrʳ} {Sp.span-arrʳ} _ = refl

module SpanFromF = Functor SpanFromF

SpansEquivF : SpanToF ⊣⊢ SpanFromF
SpansEquivF = withZig record
  { unit   = unit
  ; counit = counit
  ; zig    = zig
  }
  where unit⇒η : ∀ a → Fin ∣ a ⇒ SpanFromF.₀ (SpanToF.₀ a) ∣
        unit⇒η 0F = 0F
        unit⇒η 1F = 0F
        unit⇒η 2F = 0F
        unit⇐η : ∀ a → Fin ∣ SpanFromF.₀ (SpanToF.₀ a) ⇒ a ∣
        unit⇐η 0F = 0F
        unit⇐η 1F = 0F
        unit⇐η 2F = 0F

        unit : idF ≃ SpanFromF ∘F SpanToF
        unit = record
          { F⇒G = ntHelper record
            { η       = unit⇒η
            ; commute = commute₁
            }
          ; F⇐G = ntHelper record
            { η       = unit⇐η
            ; commute = commute₂
            }
          ; iso = iso
          }
          where open Mor Span
                commute₁ : ∀ (f : Fin ∣ a ⇒ b ∣) → unit⇒η b ∘ f ≡ SpanFromF.₁ (SpanToF.₁ f) ∘ unit⇒η a
                commute₁ {0F} {0F} 0F = refl
                commute₁ {0F} {1F} 0F = refl
                commute₁ {0F} {2F} 0F = refl
                commute₁ {1F} {1F} 0F = refl
                commute₁ {2F} {2F} 0F = refl
                commute₂ : ∀ (f : Fin ∣ a ⇒ b ∣) → unit⇐η b ∘ SpanFromF.₁ (SpanToF.₁ f) ≡ f ∘ unit⇐η a
                commute₂ {0F} {0F} 0F = refl
                commute₂ {0F} {1F} 0F = refl
                commute₂ {0F} {2F} 0F = refl
                commute₂ {1F} {1F} 0F = refl
                commute₂ {2F} {2F} 0F = refl

                iso : ∀ a → Iso (unit⇒η a) (unit⇐η a)
                iso 0F = record
                  { isoˡ = refl
                  ; isoʳ = refl
                  }
                iso 1F = record
                  { isoˡ = refl
                  ; isoʳ = refl
                  }
                iso 2F = record
                  { isoˡ = refl
                  ; isoʳ = refl
                  }

        counit⇒η : ∀ X → Sp.Span [ Functor.F₀ (SpanToF ∘F SpanFromF) X , X ]
        counit⇒η Sp.center = Sp.span-id
        counit⇒η Sp.left   = Sp.span-id
        counit⇒η Sp.right  = Sp.span-id

        counit⇐η : ∀ X → Sp.Span [ X , Functor.F₀ (SpanToF ∘F SpanFromF) X ]
        counit⇐η Sp.center = Sp.span-id
        counit⇐η Sp.left   = Sp.span-id
        counit⇐η Sp.right  = Sp.span-id

        counit : SpanToF ∘F SpanFromF ≃ idF
        counit = record
          { F⇒G = ntHelper record
            { η       = counit⇒η
            ; commute = commute₁
            }
          ; F⇐G = ntHelper record
            { η       = counit⇐η
            ; commute = commute₂
            }
          ; iso = iso
          }
          where open Mor Sp.Span
                commute₁ : ∀ {X Y} (f : Sp.SpanArr X Y) →
                             Sp.span-compose (counit⇒η Y) (SpanToF.₁ (SpanFromF.₁ f)) ≡ Sp.span-compose f (counit⇒η X)
                commute₁ {Sp.center} {.Sp.center} Sp.span-id   = refl
                commute₁ {Sp.left} {.Sp.left} Sp.span-id       = refl
                commute₁ {Sp.right} {.Sp.right} Sp.span-id     = refl
                commute₁ {.Sp.center} {.Sp.left} Sp.span-arrˡ  = refl
                commute₁ {.Sp.center} {.Sp.right} Sp.span-arrʳ = refl

                commute₂ : ∀ {X Y} (f : Sp.SpanArr X Y) →
                             Sp.span-compose (counit⇐η Y) f ≡ Sp.span-compose (SpanToF.₁ (SpanFromF.₁ f)) (counit⇐η X)
                commute₂ {Sp.center} {.Sp.center} Sp.span-id   = refl
                commute₂ {Sp.left} {.Sp.left} Sp.span-id       = refl
                commute₂ {Sp.right} {.Sp.right} Sp.span-id     = refl
                commute₂ {.Sp.center} {.Sp.left} Sp.span-arrˡ  = refl
                commute₂ {.Sp.center} {.Sp.right} Sp.span-arrʳ = refl

                iso : ∀ X → Iso (counit⇒η X) (counit⇐η X)
                iso Sp.center = record
                  { isoˡ = refl
                  ; isoʳ = refl
                  }
                iso Sp.left   = record
                  { isoˡ = refl
                  ; isoʳ = refl
                  }
                iso Sp.right  = record
                  { isoˡ = refl
                  ; isoʳ = refl
                  }

        zig : ∀ {a} → Sp.span-compose (counit⇒η (SpanToF.₀ a)) (SpanToF.₁ (unit⇒η a)) ≡ Sp.span-id
        zig {0F} = refl
        zig {1F} = refl
        zig {2F} = refl

SpansEquiv : ⊣Equivalence Span Sp.Span
SpansEquiv = record { L⊣⊢R = SpansEquivF }

module SpansEquiv = ⊣Equivalence SpansEquiv


{-# OPTIONS --rewriting --prop #-}

open import common

open import syntx as N
open import derivability as N2
open import typingrules
open import structuralrules
open import typetheories
open import examples

open import traditional as T

Σ : Signature
Σ = TTSig ΠUEl-TT

{- Maps between expressions -}

T→N : {n : ℕ} {k : SyntaxSort} → T.Expr k n → N.Expr Σ n k
T→N uu = sym 1 []
T→N (el v) = sym 0 ([] , T→N v)
T→N (pi A B) = sym 4 ([] , T→N A , T→N B)
T→N (var x) = var x
T→N (lam A B u) = sym 3 ([] , T→N A , T→N B , T→N u)
T→N (app A B f a) = sym 2 ([] , T→N A , T→N B , T→N f , T→N a)

N→T : {n : ℕ} {k : SyntaxSort} → N.Expr Σ n k → T.Expr k n
N→T (var x) = var x
N→T (sym (prev (prev (prev (prev new)))) ([] , A , B)) = pi (N→T A) (N→T B)
N→T (sym (prev (prev (prev new))) ([] , A , B , u)) = lam (N→T A) (N→T B) (N→T u)
N→T (sym (prev (prev new)) ([] , A , B , f , a)) = app (N→T A) (N→T B) (N→T f) (N→T a)
N→T (sym (prev new) []) = uu
N→T (sym new ([] , v)) = el (N→T v)

{- Equalities -}

TNT : {n : ℕ} {k : SyntaxSort} (e : N.Expr Σ n k) → T→N (N→T e) ≡ e
TNT (var x) = refl
TNT (sym (prev (prev (prev (prev new)))) ([] , A , B)) = ap2 (λ x y → sym 4 ([] , x , y)) (TNT A) (TNT B)
TNT (sym (prev (prev (prev new))) ([] , A , B , u)) = ap3 (λ x y z → sym 3 ([] , x , y , z)) (TNT A) (TNT B) (TNT u)
TNT (sym (prev (prev new)) ([] , A , B , f , a)) = ap4 (λ x y z t → sym 2 ([] , x , y , z , t)) (TNT A) (TNT B) (TNT f) (TNT a)
TNT (sym (prev new) []) = refl
TNT (sym new ([] , v)) = ap (λ v → sym 0 ([] , v)) (TNT v)

NTN : {n : ℕ} {k : SyntaxSort} (e : T.Expr k n) → N→T (T→N e) ≡ e
NTN uu = refl
NTN (el v) = ap el (NTN v)
NTN (pi A B) = ap2 pi (NTN A) (NTN B)
NTN (var x) = refl
NTN (lam A B u) = ap3 lam (NTN A) (NTN B) (NTN u)
NTN (app A B f a) = ap4 app (NTN A) (NTN B) (NTN f) (NTN a)

{- Derivability -}

data NJudgment : Set where
  njudgment : {n : ℕ} (Γ : N.Ctx Σ n) {k : JudgmentSort} → N2.Judgment Σ Γ 0 k → NJudgment

NDerivable : NJudgment → Prop
NDerivable (njudgment Γ j) = N2.Derivable (TTDer ΠUEl-TT) j

-- record NJudgment : Set where
--   constructor njudgment
--   field
--     {NJn} : ℕ
--     NJΓ : N.Ctx (TTSig ΠUEl-TT4)  NJn
--     {NJk} : JudgmentSort
--     NJj : N2.Judgment (TTSig ΠUEl-TT4) NJΓ 0 NJk

-- open NJudgment

-- record NDerivable (j : NJudgment) : Prop where
--   constructor ´_

--   field
--     `_ : N2.Derivable (TTDer ΠUEl-TT4) (NJj j)

-- open NDerivable

--   -- `_ : NDerivable (njudgment Γ j) → N2.Derivable (TTDer ΠUEl-TT) j
--   -- `_ d = d

--   -- ´_ : {n : ℕ} {Γ : N.Ctx Σ n} {k : JudgmentSort} {j : N2.Judgment Σ Γ 0 k} → N2.Derivable (TTDer ΠUEl-TT) j → NDerivable (njudgment Γ j)
--   -- ´_ d = d

NDerivable= : {j j' : NJudgment} (j= : j ≡ j') → NDerivable j' → NDerivable j
NDerivable= refl x = x

NDerivable=! : {j j' : NJudgment} (j= : j ≡ j') → NDerivable j → NDerivable j'
NDerivable=! refl x = x

T→NCtx : {n : ℕ} → T.Ctx n → N.Ctx Σ n
T→NCtx ◇ = ◇
T→NCtx (Γ , A) = (T→NCtx Γ , T→N A)

T→NJ : T.Judgment → NJudgment
T→NJ (Γ ⊢ A) = njudgment (T→NCtx Γ) (◇ ⊢ T→N A)
T→NJ (Γ ⊢ u :> A) = njudgment (T→NCtx Γ) (◇ ⊢ T→N u :> T→N A)
T→NJ (Γ ⊢ A == B) = njudgment (T→NCtx Γ) (◇ ⊢ T→N A == T→N B)
T→NJ (Γ ⊢ u == v :> A) = njudgment (T→NCtx Γ) (◇ ⊢ T→N u == T→N v :> T→N A)

weaken-comm : {k : SyntaxSort} {n : ℕ} {A : T.Expr k n} (p : WeakPos n) → N.weaken p (T→N A) ≡ T→N (T.weaken p A)
weaken-comm {A = uu} p = refl
weaken-comm {A = el v} p = ap (λ z → sym new ([] , z)) (weaken-comm p)
weaken-comm {A = pi A B} p = ap2 (λ z z' → sym (prev (prev (prev (prev new)))) ([] , z , z')) (weaken-comm p) (weaken-comm (prev p))
weaken-comm {A = var x} p = refl --ap var (weakenV-comm p x)
weaken-comm {A = lam A B u} p = ap3 (λ z z' z'' → sym (prev (prev (prev new))) ([] , z , z' , z'')) (weaken-comm p) (weaken-comm (prev p)) (weaken-comm (prev p))
weaken-comm {A = app A B f a} p = ap4 (λ z z' z'' z''' → sym (prev (prev new)) ([] , z , z' , z'' , z''')) (weaken-comm p) (weaken-comm (prev p)) (weaken-comm p) (weaken-comm p)

VarPos→ℕ : {n : ℕ} → VarPos n → ℕ
VarPos→ℕ last = 0
VarPos→ℕ (prev k) = suc (VarPos→ℕ k)

fst-VarPos→ℕ : {Σ : Signature} {n : ℕ} (k : VarPos n) (Γ : N.Ctx Σ n) {def : _} → fst (N.get (VarPos→ℕ k) Γ $ def) ≡ k
fst-VarPos→ℕ last (Γ , A) = refl
fst-VarPos→ℕ (prev k) (Γ , A) = ap prev (fst-VarPos→ℕ k Γ)

snd-VarPos→ℕ : {n : ℕ} (k : VarPos n) (Γ : T.Ctx n) {def : _} → snd (N.get (VarPos→ℕ k) (T→NCtx Γ) $ def) ≡ T→N (T.get k Γ)
snd-VarPos→ℕ last (Γ , A) = weaken-comm last
snd-VarPos→ℕ (prev k) (Γ , A) = ap (N.weaken last) (snd-VarPos→ℕ k Γ) ∙ weaken-comm last

get-def : {n : ℕ} (k : VarPos n) (Γ : T.Ctx n) → isDefined (N.get (VarPos→ℕ k) (T→NCtx Γ))
get-def last (Γ , A) = tt
get-def (prev k) (Γ , A) = (get-def k Γ , tt)

MorInsert : {Σ : Signature} (x : WeakPos m) (δ : N.Mor Σ n m) (u : N.TmExpr Σ n) → N.Mor Σ n (suc m)
MorInsert last δ u = (δ , u)
MorInsert (prev x) (δ , v) u = (MorInsert x δ u , v)

{-# REWRITE +O-rewrite #-}
{-# REWRITE +S-rewrite #-}
{-# REWRITE assoc #-}

weaken-MorInsert : {Σ : Signature} {n k : ℕ} {x : WeakPos n} {δ : N.Mor Σ k n} {u : N.TmExpr Σ k}
                 → N.weakenMor (MorInsert x δ u) ≡ MorInsert x (N.weakenMor δ) (N.weaken last u)
weaken-MorInsert {x = last} = refl
weaken-MorInsert {x = prev x} {δ , u} = ap2 _,_ weaken-MorInsert refl

Impossible : {n k : ℕ} {A : Prop} → suc (n + k) ≤ n → A
Impossible {suc n} {k = zero} (≤S p) = Impossible p
Impossible {suc n} {k = suc k} p = Impossible (≤P p)

weakenV-η : (x : WeakPos n) (y : VarPos n) {p : n ≤ n} → y ≡ weakenV {{p}} x y
weakenV-η x y {≤r} = ! weakenV≤r
weakenV-η x y {≤S p} = Impossible p

weaken-η  : {Σ : Signature} {k : _} {x : _} {p : n ≤ n} {u : N.Expr Σ n k} → u ≡ N.weaken {{p}} x u
weakenA-η : {Σ : Signature} {k : _} {x : _} {p : n ≤ n} {u : N.Args Σ n k} → u ≡ N.weakenA {{p}} x u

weaken-η {x = x} {u = var y} = ap var (weakenV-η x y)
weaken-η {u = sym s us} = ap (sym s) weakenA-η

weakenA-η {u = []} = refl
weakenA-η {u = u , x} = ap2 _,_ weakenA-η weaken-η

WeakPosIncl : {n m : ℕ} {{_ : n ≤ m}} → WeakPos n → WeakPos m
WeakPosIncl last = last
WeakPosIncl {m = suc m} {{p}} (prev x) = prev (WeakPosIncl {{≤P p}} x)

≤P-≤SS : {n m : ℕ} (p : n ≤ m) → p ≡ ≤P (≤SS {{p}})
≤P-≤SS ≤r = refl
≤P-≤SS (≤S p) = ap ≤S (≤P-≤SS _)

WeakPosIncl-comm : {n m k : ℕ} {{p : n ≤ m}} {x : WeakPos n} → weakenPos (≤-+ {m = k}) (WeakPosIncl {{p}} x) ≡ WeakPosIncl {{≤+ k {{p}}}} (weakenPos ≤-+ x)
WeakPosIncl-comm {k = zero} {x = last} = refl
WeakPosIncl-comm {k = suc k} {x = last} = ap prev (WeakPosIncl-comm {k = k} {x = last} ∙ ap (λ z → WeakPosIncl {{z}} (weakenPos ≤-+ last)) (≤P-≤SS _))
WeakPosIncl-comm {m = suc m} {zero} {x = prev x} = refl
WeakPosIncl-comm {m = suc m} {suc k} {x = prev x} = ap prev (WeakPosIncl-comm {m = suc m} {k = k} {x = prev x} ∙ ap (λ z → WeakPosIncl {{z}} (weakenPos ≤-+ (prev x))) (≤P-≤SS _))

≤-ishProp : {n m : ℕ} (p q : n ≤ m) → p ≡ q
≤-ishProp ≤r ≤r = refl
≤-ishProp ≤r (≤S q) = Impossible q
≤-ishProp (≤S p) ≤r = Impossible p
≤-ishProp (≤S p) (≤S q) = ap ≤S (≤-ishProp p q)

weakenV-μ : {n m k : ℕ} {{p : n ≤ m}} {{q : m ≤ k}} {{r : n ≤ k}} {x : VarPos n} {y : WeakPos n}
            → weakenV {{q}} (WeakPosIncl y) (weakenV {{p}} y x) ≡ weakenV {{r}} y x
weakenV-μ ⦃ p = ≤r ⦄ ⦃ ≤r ⦄ ⦃ ≤r ⦄ = weakenV≤r
weakenV-μ ⦃ p = ≤r ⦄ ⦃ ≤r ⦄ ⦃ ≤S r ⦄ = Impossible r
weakenV-μ ⦃ p = ≤r ⦄ ⦃ ≤S q ⦄ ⦃ ≤r ⦄ = Impossible q
weakenV-μ ⦃ p = ≤r ⦄ ⦃ ≤S q ⦄ ⦃ ≤S r ⦄ {x} {y = last} = ap2 (λ z z' → prev (weakenV ⦃ z ⦄ last z')) (≤-ishProp _ _) weakenV≤r
weakenV-μ ⦃ p = ≤r ⦄ ⦃ ≤S q ⦄ ⦃ ≤S r ⦄ {last} {y = prev y} = refl
weakenV-μ ⦃ p = ≤r ⦄ ⦃ ≤S q ⦄ ⦃ ≤S r ⦄ {prev x} {y = prev y} = ap prev (ap (weakenV {{≤P (≤S q)}} (WeakPosIncl y)) (! weakenV≤r) ∙ weakenV-μ {{≤r}} {{≤P (≤S q)}} {{≤P (≤S r)}} {x = x} {y})
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤r ⦄ ⦃ ≤r ⦄ = Impossible p
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤r ⦄ ⦃ ≤S r ⦄ {x} {y} = weakenV≤r {p = WeakPosIncl {{≤S p}} y} {v = weakenV {{≤S p}} y x} ∙ ap (λ z → weakenV ⦃ z ⦄ y x) (≤-ishProp _ _) --
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤S q ⦄ ⦃ ≤r ⦄ = Impossible (≤tr {{≤S p}} {{q}})
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤S q ⦄ ⦃ ≤S ≤r ⦄ = Impossible (≤tr {{q}} {{p}})
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤S q ⦄ ⦃ ≤S (≤S r) ⦄ {x} {y = last} = ap prev (weakenV-μ {{≤S p}} {{q}} {{≤S r}} {x} {last})
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤S q ⦄ ⦃ ≤S (≤S r) ⦄ {last} {y = prev y} = refl
weakenV-μ ⦃ p = ≤S p ⦄ ⦃ ≤S q ⦄ ⦃ ≤S (≤S r) ⦄ {prev x} {y = prev y} = ap prev (weakenV-μ {{≤P (≤S p)}} {{≤P (≤S q)}} {{≤P (≤S (≤S r))}} {x} {y})

weaken-μ  : {Σ : Signature} {k : _} {x : WeakPos n} {q : n ≤ m} {r : _} {u : N.Expr Σ n k} → N.weaken  {{≤S ≤r}} (WeakPosIncl {{q}} x) (N.weaken  {{q}} x u) ≡ N.weaken  {{r}} x u
weakenA-μ : {Σ : Signature} {k : _} {x : WeakPos n} {q : n ≤ m} {r : _} {u : N.Args Σ n k} → N.weakenA {{≤S ≤r}} (WeakPosIncl {{q}} x) (N.weakenA {{q}} x u) ≡ N.weakenA {{r}} x u

weaken-μ {x = y} {q = p} {u = var x} = ap var ((weakenV-μ {{p}} {{≤S ≤r}} {{_}} {x = x} {y = y}))
weaken-μ {u = sym s x} = ap (sym s) weakenA-μ

weakenA-μ {u = []} = refl
weakenA-μ {q = q} {u = u , x} = ap2 _,_ weakenA-μ (ap2 (λ z z' → N.weaken {{z}} z' (N.weaken {{≤+ _ {{q}}}} _ x))
                                                       (≤-ishProp _ _)
                                                       (WeakPosIncl-comm {{q}})
                                                   ∙ weaken-μ {q = ≤+ _ {{q}}})

weaken+-MorInsert : {Σ : Signature} (m : ℕ) {n k : ℕ} {x : WeakPos n} {δ : N.Mor Σ k n} {u : N.TmExpr Σ k}
                    → N.weakenMor+ m (MorInsert x δ u) ≡ MorInsert (weakenPos ≤-+ x) (N.weakenMor+ m δ) (N.weaken last u)
weaken+-MorInsert zero = ap (MorInsert _ _) weaken-η
weaken+-MorInsert (suc m) = ap2 _,_ (ap N.weakenMor (weaken+-MorInsert m) ∙ weaken-MorInsert ∙ ap (MorInsert _ _) weaken-μ) refl

SubstV-insert : {n m : ℕ} {y : VarPos n} {x : WeakPos n} {u : N.TmExpr Σ m} {δ : N.Mor Σ m n} {p : n ≤ suc n}
                → SubstMor (var (weakenV {{p}} x y)) (MorInsert x δ u) ≡ SubstMor (var y) δ
SubstV-insert {x = last} {δ = δ} {p = ≤S ≤r} = ap (λ z → SubstMor (var z) δ) weakenV≤r
SubstV-insert {y = last} {x = prev x} {δ = δ , v} {p = ≤S ≤r} = refl
SubstV-insert {y = prev y} {x = prev x} {u} {δ = δ , v} {p = ≤S ≤r} = SubstV-insert {y = y} {x = x} {u = u} {δ = δ} {p = ≤S ≤r}
SubstV-insert {p = ≤S (≤S p)} = Impossible p

Subst-insert  : {k : SyntaxSort} {n m : ℕ} {e : N.Expr Σ n k} {x : WeakPos n} {u : N.TmExpr Σ m} {δ : N.Mor Σ m n} {p : _}
                → SubstMor (N.weaken {{p}} x e) (MorInsert x δ u) ≡ SubstMor e δ
SubstA-insert : {args : SyntaxArityArgs} {n m : ℕ} {es : N.Args Σ n args} {x : WeakPos n} {u : N.TmExpr Σ m} {δ : N.Mor Σ m n} {p : _}
                → SubstAMor (N.weakenA {{p}} x es) (MorInsert x δ u) ≡ SubstAMor es δ

Subst-insert {e = var x} {x = x'} {u} {p = p} = SubstV-insert {x = x'} {u} {p = p}
Subst-insert {e = sym s x} = ap (sym s) SubstA-insert

SubstA-insert {es = []} = refl
SubstA-insert {args} {n} {es = _,_ {m = m} es e} {x = x} {u = u} {p = p} =
  ap2 _,_ SubstA-insert (ap (SubstMor (N.weaken {{≤+ m {n} {suc n} {{p}}}} (weakenPos ≤-+ x) e)) (weaken+-MorInsert m) ∙ Subst-insert {e = e} {x = weakenPos ≤-+ x})

weakenMor+-idMor : {n : ℕ} (m : ℕ) → N.weakenMor+ m (N.idMor {Σ = Σ} {n = n}) ≡ N.idMor
weakenMor+-idMor zero = refl
weakenMor+-idMor (suc m) = ap2 _,_ (ap N.weakenMor (weakenMor+-idMor m)) refl

SubstMor-weakenMor : {x : VarPos n} {δ : N.Mor Σ m n} → SubstMor (var x) (N.weakenMor δ) ≡ N.weaken last (SubstMor (var x) δ)
SubstMor-weakenMor {x = last} {δ , u} = refl
SubstMor-weakenMor {x = prev x} {δ , u} = SubstMor-weakenMor {x = x} {δ}

SubstMor-idMor  : {n : ℕ} {k : _} (e  : N.Expr Σ n k) → SubstMor e N.idMor ≡ e
SubstAMor-idMor : {n : ℕ} {k : _} (es : N.Args Σ n k) → SubstAMor es N.idMor ≡ es

SubstMor-idMor (var last) = refl
SubstMor-idMor (var (prev x)) = SubstMor-weakenMor {x = x} {δ = N.idMor} ∙ ap (N.weaken last) (SubstMor-idMor (var x)) ∙ ap var (ap prev weakenV≤r)
SubstMor-idMor (sym s es) = ap (sym s) (SubstAMor-idMor es)

SubstAMor-idMor [] = refl
SubstAMor-idMor (_,_ {m = m} es x) = ap2 _,_ (SubstAMor-idMor es) (ap (SubstMor x) (weakenMor+-idMor m) ∙ SubstMor-idMor x)

Subst-insert-idMor : {k : SyntaxSort} {e : N.Expr Σ n k} {x : WeakPos n} {u : N.TmExpr Σ n} {p : _}
                    → SubstMor (N.weaken {{p}} x e) (MorInsert x N.idMor u) ≡ e
Subst-insert-idMor {e = e} {x} {u} {p} = Subst-insert {e = e} {x} {u} {N.idMor} {p} ∙ SubstMor-idMor e

inj : WeakPos n → WeakPos (suc n)
inj last = last
inj (prev x) = prev (inj x)

weakenPos-inj : {m : ℕ} (x : WeakPos n) → weakenPos (≤-+ {m = m}) (inj x) ≡ inj (weakenPos ≤-+ x)
weakenPos-inj {m = zero} x = refl
weakenPos-inj {m = suc m} last = ap prev (weakenPos-inj last)
weakenPos-inj {m = suc m} (prev x) = ap prev (weakenPos-inj (prev x))

SubstV-insert2 : {n m : ℕ} {y : VarPos n} {x : WeakPos n} {u : N.TmExpr Σ (suc m)} {δ : N.Mor Σ (suc m) (suc n)} {p : _}
                → SubstMor (var (weakenV {{≤S p}} x y)) (MorInsert (inj x) δ u) ≡ SubstMor (var (weakenV {{p}} x y)) δ
SubstV-insert2 {y = last} {last} = refl
SubstV-insert2 {y = prev y} {last} = refl
SubstV-insert2 {y = last} {prev x} {δ = δ , u} = refl
SubstV-insert2 {y = prev y} {prev x} {δ = δ , u} {≤S ≤r} = SubstV-insert2 {y = y} {x = x} {δ = δ}
SubstV-insert2 {y = prev y} {prev x} {δ = δ , u} {≤S (≤S p)} = Impossible p

Subst-insert2  : {k : SyntaxSort} {n m : ℕ} {e : N.Expr Σ n k} {x : WeakPos n} {u : N.TmExpr Σ (suc m)} {δ : N.Mor Σ (suc m) (suc n)} {p : _}
                 → SubstMor (N.weaken {{≤S p}} x e) (MorInsert (inj x) δ u) ≡ SubstMor (N.weaken {{p}} x e) δ
SubstA-insert2  : {args : SyntaxArityArgs} {n m : ℕ} {es : N.Args Σ n args} {x : WeakPos n} {u : N.TmExpr Σ (suc m)} {δ : N.Mor Σ (suc m) (suc n)} {p : _}
                 → SubstAMor (N.weakenA {{≤S p}} x es) (MorInsert (inj x) δ u) ≡ SubstAMor (N.weakenA {{p}} x es) δ

Subst-insert2 {e = var y} {x = x} = SubstV-insert2 {y = y} {x = x}
Subst-insert2 {e = sym s es} = ap (sym s) SubstA-insert2

SubstA-insert2 {es = []} = refl
SubstA-insert2 {n = n} {m = m'} {es = _,_ {m = m} es e} {x = x} {u = u} =
  ap2 _,_ SubstA-insert2 ((ap (SubstMor (N.weaken {{_}} (weakenPos ≤-+ x) e)) (weaken+-MorInsert m ∙ ap3 MorInsert (weakenPos-inj x) refl refl)
                          ∙ ap
                              (λ z →
                                 SubstMor (N.weaken ⦃ z ⦄ (weakenPos ≤-+ x) e)
                                 (MorInsert (inj (weakenPos ≤-+ x)) (N.weakenMor+ m {n = suc n} {m = suc m'} _)
                                  (N.weaken last u)))
                              (≤-ishProp _ _) ∙ Subst-insert2 {e = e} {x = weakenPos ≤-+ x} {u = N.weaken last u}))

Subst-insert-idMor2 : {k : SyntaxSort} {e : N.Expr Σ n k} {x : WeakPos n} {u : N.TmExpr Σ (suc n)}
                    → SubstMor (N.weaken x e) (MorInsert (inj x) (N.idMor {n = suc n}) u) ≡ N.weaken {{≤S ≤r}} x e
Subst-insert-idMor2 {e = e} {x} {u} = Subst-insert2 {e = e} {x} {u} {N.idMor} ∙ SubstMor-idMor _

T→NMor : T.Mor n m → N.Mor Σ n m
T→NMor ◇ = ◇
T→NMor (δ , u) = (T→NMor δ , T→N u)

weakenMor-comm : {δ : T.Mor n m} → N.weakenMor (T→NMor δ) ≡ T→NMor (T.weakenMor δ)
weakenMor-comm {δ = ◇} = refl
weakenMor-comm {δ = δ , u} = ap2 _,_ weakenMor-comm (weaken-comm last)

substV-lemma : (x : VarPos n) {δ : T.Mor m n} → SubstMor (var x) (T→NMor δ) ≡ T→N (var x [ δ ])
substV-lemma last {δ , u} = refl
substV-lemma (prev x) {δ , u} = substV-lemma x

subst-lemma : {k : _} (B : T.Expr k n) {δ : T.Mor m n} → SubstMor (T→N B) (T→NMor δ) ≡ T→N (B [ δ ])
subst-lemma uu = refl
subst-lemma (el v) = ap (λ z → sym new ([] , z)) (subst-lemma v)
subst-lemma (pi A B) = ap2 (λ z z' → sym (prev (prev (prev (prev new)))) ([] , z , z')) (subst-lemma A) (ap (SubstMor (T→N B)) (ap2 _,_ weakenMor-comm refl) ∙ subst-lemma B)
subst-lemma (var x) = substV-lemma x
subst-lemma (lam A B u) = ap3 (λ z z' z'' → sym (prev (prev (prev new))) ([] , z , z' , z''))
                            (subst-lemma A) (ap (SubstMor (T→N B)) (ap2 _,_ weakenMor-comm refl) ∙ subst-lemma B) (ap (SubstMor (T→N u)) (ap2 _,_ weakenMor-comm refl) ∙ subst-lemma u)
subst-lemma (app A B f a) = ap4
                              (λ z z' z'' z''' →
                                 sym (prev (prev new)) ([] , z , z' , z'' , z'''))
                              (subst-lemma A) (ap (SubstMor (T→N B)) (ap2 _,_ weakenMor-comm refl) ∙ subst-lemma B) (subst-lemma f) (subst-lemma a)

idMor-lemma : {n : ℕ} → N.idMor {n = n} ≡ T→NMor T.idMor
idMor-lemma {zero} = refl
idMor-lemma {suc n} = ap2 _,_ (ap N.weakenMor idMor-lemma ∙ weakenMor-comm) refl

Subst-T→N : {k : _} (B : T.Expr k (suc n)) (a : T.TmExpr n) → N.SubstMor (T→N B) (N.idMor , T→N a) ≡ T→N (T.subst B a)
Subst-T→N B a = ap (λ z → SubstMor (T→N B) (z , T→N a)) idMor-lemma ∙ subst-lemma B

-- T→NDer : {j : T.Judgment} → T.Derivable j → NDerivable (T→NJ j)
-- T→NDer (Var {Γ = Γ} k dA) = NDerivable=! (ap (λ x → njudgment (T→NCtx Γ) (◇ ⊢ var x :> T→N (T.get k Γ))) (fst-VarPos→ℕ k (T→NCtx Γ))) (´ apr S (var (VarPos→ℕ k)) ([] ,0Ty ` T→NDer dA) {{get-def k Γ , (snd-VarPos→ℕ k Γ , tt)}})
-- T→NDer (TyRefl dA) = ´ apr S tyRefl ([] , ` T→NDer dA)
-- T→NDer (TySymm dA=) = ´ apr S tySymm ([] , ` T→NDer dA=)
-- T→NDer (TyTran dA= dB=) = ´ apr S tyTran ([] , ` T→NDer dA= , ` T→NDer dB=)
-- T→NDer (TmRefl du) = ´ apr S tmRefl ([] , ` T→NDer du)
-- T→NDer (TmSymm du=) = ´ apr S tmSymm ([] , ` T→NDer du=)
-- -- T→NDer (TmTran du= dv=) = apr S tmTran ([] , T→NDer du= , T→NDer dv=)
-- -- T→NDer (Conv du dA=) = apr S conv ([] , T→NDer du , T→NDer dA=)
-- -- T→NDer (ConvEq du= dA=) = apr S convEq ([] , T→NDer du= , T→NDer dA=)
-- -- T→NDer UU = apr T 1 []
-- -- T→NDer UUCong = apr C 1 []
-- -- T→NDer (El dv) = apr T 0 ([] ,0Tm T→NDer dv)
-- -- T→NDer (ElCong dv=) = apr C 0 ([] ,0Tm= T→NDer dv=)
-- -- T→NDer (Pi dA dB) = apr T 4 ([] ,0Ty T→NDer dA ,1Ty T→NDer dB)
-- -- T→NDer (PiCong dA= dB=) = apr C 4 ([] ,0Ty= T→NDer dA= ,1Ty= T→NDer dB=)
-- -- T→NDer (Lam {A = A} {B = B} {u = u} dA dB du) =
-- --   NDerivable=! (ap (λ z → njudgment _ (◇ ⊢ sym (prev (prev (prev new))) ([] , T→N _ , T→N _ , T→N _) :> sym (prev (prev (prev (prev new)))) ([] , T→N _ , z))) Subst-insert-idMor)
-- --                (apr T 3 ([] ,0Ty T→NDer dA ,1Ty T→NDer dB ,1Tm NDerivable= (ap (λ z → njudgment _ (◇ ⊢ T→N _ :> z)) Subst-insert-idMor) (T→NDer du)))
-- -- T→NDer (LamCong dA= dB= du=) =
-- --   NDerivable=! (ap (λ z → njudgment _ (◇ ⊢ sym (prev (prev (prev new))) ([] , T→N _ , T→N _ , T→N _) == sym (prev (prev (prev new))) ([] , T→N _ , T→N _ , T→N _) :> sym (prev (prev (prev (prev new)))) ([] , T→N _ , z)))
-- --                    Subst-insert-idMor)
-- --     (apr C 3 ([] ,0Ty= T→NDer dA= ,1Ty= T→NDer dB= ,1Tm= NDerivable= (ap (λ z → njudgment _ (◇ ⊢ T→N _ == T→N _ :> z)) Subst-insert-idMor) (T→NDer du=)))
-- -- T→NDer (App {A = A} {B} {f} {a} dA dB df da) =
-- --   NDerivable=! (ap (λ z → njudgment _ (◇ ⊢ sym (prev (prev new)) ([] , T→N A , T→N B , T→N f , T→N a) :> z)) (Subst-T→N B a))
-- --     (apr T 2 ([] ,0Ty T→NDer dA
-- --                  ,1Ty T→NDer dB
-- --                  ,0Tm NDerivable= (ap (λ z → njudgment _ (◇ ⊢ T→N f :> sym (prev (prev (prev (prev new)))) ([] , T→N A , z))) Subst-insert-idMor) (T→NDer df)
-- --                  ,0Tm T→NDer da))
-- -- T→NDer (AppCong {A = A} {A' = A'} {B = B} {B' = B'} {f = f} {f' = f'} {a = a} {a' = a'} dA= dB= df= da=) =
-- --   NDerivable=! (ap (λ z → njudgment _ (◇ ⊢ sym (prev (prev new)) ([] , T→N A , T→N B , T→N f , T→N a) == sym (prev (prev new)) ([] , T→N A' , T→N B' , T→N f' , T→N a') :> z)) (Subst-T→N B a))
-- --     (apr C 2 ([] ,0Ty= T→NDer dA=
-- --                  ,1Ty= T→NDer dB=
-- --                  ,0Tm= NDerivable= (ap (λ z → njudgment _ (◇ ⊢ T→N f == T→N f' :> sym (prev (prev (prev (prev new)))) ([] , T→N A , z))) Subst-insert-idMor)
-- --                                    (T→NDer df=)
-- --                  ,0Tm= T→NDer da=))
-- -- T→NDer (BetaPi {A = A} {B = B} {u = u} {a = a} dA dB du da) =
-- --   NDerivable=! (ap4
-- --                   (λ z z' z'' z''' →
-- --                      njudgment _
-- --                      (◇ ⊢
-- --                       sym (prev (prev new))
-- --                       ([] , T→N A , z ,
-- --                        sym (prev (prev (prev new))) ([] , T→N A , z , z')
-- --                        , T→N a)
-- --                       == z'' :> z'''))
-- --                   Subst-insert-idMor Subst-insert-idMor (Subst-T→N u a) (Subst-T→N B a))
-- --                (apr Eq 1 ([] ,0Ty T→NDer dA ,1Ty T→NDer dB ,1Tm NDerivable= (ap (λ z → njudgment _ (◇ ⊢ T→N u :> z)) Subst-insert-idMor) (T→NDer du) ,0Tm T→NDer da))
-- -- T→NDer (EtaPi {n = n} {A = A} {B = B} {f = f} dA dB df) =
-- --   NDerivable=! (ap4
-- --                   (λ z z' z'' z''' →
-- --                      njudgment _
-- --                      (◇ ⊢ T→N f ==
-- --                       sym (prev (prev (prev new)))
-- --                       ([] , T→N A , z ,
-- --                        sym (prev (prev new)) ([] , z' , z'' , z''' , var last))
-- --                       :> sym (prev (prev (prev (prev new)))) ([] , T→N A , z)))
-- --                   Subst-insert-idMor (weaken-comm last) (Subst-insert-idMor2 ∙ weaken-comm (prev last)) (weaken-comm last))
-- --                (apr Eq 0 ([] ,0Ty T→NDer dA
-- --                              ,1Ty T→NDer dB
-- --                              ,0Tm NDerivable= (ap (λ z → njudgment _ (◇ ⊢ T→N f :> sym (prev (prev (prev (prev new)))) ([] , T→N A , z))) Subst-insert-idMor) (T→NDer df)))

N→TCtx : {n : ℕ} → N.Ctx Σ n → T.Ctx n
N→TCtx ◇ = ◇
N→TCtx (Γ , A) = (N→TCtx Γ , N→T A)

N→TMor : {n m : ℕ} → N.Mor Σ n m → T.Mor n m
N→TMor ◇ = ◇
N→TMor (δ , u) = (N→TMor δ , N→T u)

weaken-comm' : {k : SyntaxSort} {n : ℕ} {A : N.Expr Σ n k} (p : WeakPos n) → N→T (N.weaken p A) ≡ T.weaken p (N→T A)
weaken-comm' p = ap N→T (ap (N.weaken p) (! (TNT _))) ∙ ap N→T (weaken-comm p) ∙ NTN _

get-eq : {n : ℕ} (k : ℕ) (Γ : N.Ctx Σ n) {def : _} → N→T (snd (N.get k Γ $ def)) ≡ T.get (fst (N.get k Γ $ def)) (N→TCtx Γ)
get-eq zero (Γ , A) = weaken-comm' last
get-eq (suc k) (Γ , A) = weaken-comm' last ∙ ap (T.weaken last) (get-eq k Γ)

N→TJ : NJudgment → T.Judgment
N→TJ (njudgment Γ (◇ ⊢ A)) = N→TCtx Γ ⊢ N→T A
N→TJ (njudgment Γ (◇ ⊢ u :> A)) = N→TCtx Γ ⊢ N→T u :> N→T A
N→TJ (njudgment Γ (◇ ⊢ A == B)) = N→TCtx Γ ⊢ N→T A == N→T B
N→TJ (njudgment Γ (◇ ⊢ u == v :> A)) = N→TCtx Γ ⊢ N→T u == N→T v :> N→T A

congTy : {Γ : T.Ctx n} {A A' : T.TyExpr n} → A ≡ A' → T.Derivable (Γ ⊢ A) → T.Derivable (Γ ⊢ A')
congTy refl d = d

congTmTy : {Γ : T.Ctx n} {u : T.TmExpr n} {A A' : T.TyExpr n} → A ≡ A' → T.Derivable (Γ ⊢ u :> A) → T.Derivable (Γ ⊢ u :> A')
congTmTy refl d = d

congTmTy! : {Γ : T.Ctx n} {u : T.TmExpr n} {A A' : T.TyExpr n} → A' ≡ A → T.Derivable (Γ ⊢ u :> A) → T.Derivable (Γ ⊢ u :> A')
congTmTy! refl d = d

congTmEqTy : {Γ : T.Ctx n} {u u' : T.TmExpr n} {A A' : T.TyExpr n} → A ≡ A' → T.Derivable (Γ ⊢ u == u' :> A) → T.Derivable (Γ ⊢ u == u' :> A')
congTmEqTy refl d = d

congTmEqTy! : {Γ : T.Ctx n} {u u' : T.TmExpr n} {A A' : T.TyExpr n} → A' ≡ A → T.Derivable (Γ ⊢ u == u' :> A) → T.Derivable (Γ ⊢ u == u' :> A')
congTmEqTy! refl d = d

congTmEq : {Γ : T.Ctx n} {u u' v v' : T.TmExpr n} {A A' : T.TyExpr n} → A ≡ A' → u ≡ u' → v ≡ v' → T.Derivable (Γ ⊢ u == v :> A) → T.Derivable (Γ ⊢ u' == v' :> A')
congTmEq refl refl refl d = d

congTmEq! : {Γ : T.Ctx n} {u u' v v' : T.TmExpr n} {A A' : T.TyExpr n} → A' ≡ A → u' ≡ u → v' ≡ v → T.Derivable (Γ ⊢ u == v :> A) → T.Derivable (Γ ⊢ u' == v' :> A')
congTmEq! refl refl refl d = d

N→T-Subst : {k : _} (B : N.Expr Σ (suc n) k) (a : N.TmExpr Σ n) → N→T (SubstMor B (N.idMor , a)) ≡ T.subst (N→T B) (N→T a)
N→T-Subst B a = ap N→T (! (ap2 SubstMor (TNT B) (ap2 _,_ refl (TNT a))) ∙ Subst-T→N (N→T B) (N→T a)) ∙ NTN _

N→TDer : {j : NJudgment} → NDerivable j → T.Derivable (N→TJ j)

-- N→TDer {njudgment Γ _} (apr S (var k) {js = [] , ◇ ⊢ A} ([] , dA) {{xᵈ , (refl , tt)}}) = congTmTy! (get-eq k Γ) (Var (fst (N.get k Γ $ xᵈ)) (congTy (get-eq k Γ) (N→TDer dA)))
-- N→TDer {njudgment Γ _} (apr S conv {js = [] , ◇ ⊢ u :> A , ◇ ⊢ A == B} ([] , du , dA=) {{refl , tt}}) = Conv (N→TDer du) (N→TDer dA=)
-- N→TDer {njudgment Γ _} (apr S convEq {js = [] , ◇ ⊢ u == v :> A , ◇ ⊢ A == B} ([] , du= , dA=) {{refl , tt}}) = ConvEq (N→TDer du=) (N→TDer dA=)
-- N→TDer {njudgment Γ _} (apr S tyRefl {js = [] , ◇ ⊢ A} ([] , dA)) = TyRefl (N→TDer dA)
-- N→TDer {njudgment Γ _} (apr S tySymm {js = [] , ◇ ⊢ A == B} ([] , dA=)) = TySymm (N→TDer dA=)
-- N→TDer {njudgment Γ _} (apr S tyTran {js = [] , ◇ ⊢ A == B , ◇ ⊢ B == D} ([] , dA= , dB=) {{refl , tt}}) = TyTran (N→TDer dA=) (N→TDer dB=)
-- N→TDer {njudgment Γ _} (apr S tmRefl {js = [] , ◇ ⊢ u :> A} ([] , du)) = TmRefl (N→TDer du)
-- N→TDer {njudgment Γ _} (apr S tmSymm {js = [] , ◇ ⊢ u == v :> A} ([] , du=)) = TmSymm (N→TDer du=)
-- N→TDer {njudgment Γ _} (apr S tmTran {js = [] , ◇ ⊢ u == v :> A , ◇ ⊢ v == w :> A} ([] , du= , dv=) {{refl , (refl , tt)}}) = TmTran (N→TDer du=) (N→TDer dv=)
-- N→TDer {njudgment Γ _} (apr T typingrule {js = [] , (◇ ⊢ v :> _)} ([] , dv) {{(tt , (tt , (refl , tt))) , tt}}) = El (N→TDer dv)
-- N→TDer {njudgment Γ _} (apr T (prev typingrule) []) = UU
-- N→TDer {njudgment Γ _} (apr T (prev (prev typingrule)) {js = [] , ◇ ⊢ A , (◇ , _) ⊢ B , (◇ ⊢ f :> _) , (◇ ⊢ a :> _)} ([] , dA , dB , df , da)
--                            {{(((((tt , (tt , tt)) , ((tt , refl) , tt)) , (tt , (refl , tt))) , (tt , (refl , tt))) , tt)}}) = congTmTy! (N→T-Subst B a) (App (N→TDer dA) (N→TDer dB) (congTmTy (ap (pi (N→T A)) (ap N→T Subst-insert-idMor)) (N→TDer df)) (N→TDer da))
-- N→TDer {njudgment Γ _} (apr T (prev (prev (prev typingrule))) {js = [] , ◇ ⊢ A , ((◇ , A) ⊢ B) , ((◇ , A) ⊢ u :> B')} ([] , dA , dB , du) {{(((tt , (tt , tt)) , ((tt , refl) , tt)) , ((tt , refl) , (refl , tt)) ) , tt}})
--   = congTmTy! (ap (pi (N→T A)) (ap N→T Subst-insert-idMor)) (Lam (N→TDer dA) (N→TDer dB) (congTmTy (ap N→T Subst-insert-idMor) (N→TDer du)))
-- N→TDer {njudgment Γ _} (apr T (prev (prev (prev (prev typingrule)))) {js = [] , ◇ ⊢ A , (◇ , ._) ⊢ B} ([] , dA , dB) {{((tt , (tt , tt)) , ((tt , refl) , tt)) , tt}}) = Pi (N→TDer dA) (N→TDer dB)
-- N→TDer {njudgment Γ _} (apr C congruencerule {js = [] , ◇ ⊢ v == v' :> _} ([] , dv=) {{((tt , (tt , (refl , tt))) , tt)}}) = ElCong (N→TDer dv=)
-- N→TDer {njudgment Γ _} (apr C (prev congruencerule) []) = UUCong
-- N→TDer {njudgment Γ _} (apr C (prev (prev congruencerule)) {js = [] , ◇ ⊢ A == A' , (◇ , _) ⊢ B == B' , (◇ ⊢ f == f' :> _) , (◇ ⊢ a == a' :> _)} ([] , dA= , dB= , df= , da=)
--   {{(((((tt , (tt , tt)) , ((tt , refl) , tt)) , (tt , (refl , tt))) , (tt , (refl , tt))) , tt)}})
--    = congTmEqTy! (N→T-Subst B a) (AppCong (N→TDer dA=) (N→TDer dB=) (congTmEqTy (ap (pi (N→T A)) (ap N→T Subst-insert-idMor)) (N→TDer df=)) (N→TDer da=))
-- N→TDer {njudgment Γ _} (apr C (prev (prev (prev congruencerule))) {js = [] , ◇ ⊢ A == A' , ((◇ , A) ⊢ B == B') , ((◇ , A) ⊢ u == u' :> B'')} ([] , dA= , dB= , du=) {{(((tt , (tt , tt)) , ((tt , refl) , tt)) , ((tt , refl) , (refl , tt)) ) , tt}}) = congTmEqTy! (ap (pi (N→T A)) (ap N→T Subst-insert-idMor)) (LamCong (N→TDer dA=) (N→TDer dB=) (congTmEqTy (ap N→T Subst-insert-idMor) (N→TDer du=)))
-- N→TDer {njudgment Γ _} (apr C (prev (prev (prev (prev congruencerule)))) {js = [] , ◇ ⊢ A == A' , (◇ , ._) ⊢ B == B'} ([] , dA= , dB=) {{(((tt , (tt , tt)) , ((tt , refl) , tt)) , tt)}}) = PiCong (N→TDer dA=) (N→TDer dB=)
-- N→TDer {njudgment Γ _} (apr Eq equalityrule js-der) = {!Eta!}
N→TDer {njudgment Γ _} (apr Eq (prev equalityrule) {js = [] , (◇ ⊢ A) , ((◇ , _) ⊢ B) , ((◇ , _) ⊢ u :> _) , (◇ ⊢ a :> _)} ([] , dA , dB , du , da)
  {{(((((tt , (tt , tt)) , ((tt , refl) , tt)) , ((tt , refl) , (refl , tt))) , (tt , (refl , tt))) , tt)}})
   = {!da --jdef --congTmEq! ? ? ? (BetaPi (N→TDer dA) (N→TDer dB) (congTmTy (ap N→T Subst-insert-idMor) (N→TDer du)) (N→TDer da))!}