------------------------------------------------------------------------
-- Some admissible rules related to identity types and quotients
------------------------------------------------------------------------

open import Definition.Typed.Restrictions
open import Graded.Modality

module Definition.Typed.Properties.Admissible.Quotient.Primitive
  {} {M : Set }
  {𝕄 : Modality M}
  (R : Type-restrictions 𝕄)
  where

open import Definition.Untyped M
open import Definition.Untyped.Identity 𝕄
open import Definition.Untyped.Properties M
open import Definition.Untyped.Quotient 𝕄

open import Definition.Typed R
open import Definition.Typed.Inversion.Primitive R
open import Definition.Typed.Properties.Admissible.Var R
open import Definition.Typed.Stability.Primitive R
open import Definition.Typed.Substitution.Primitive.Primitive R
open import Definition.Typed.Properties.Well-formed R
open import Definition.Typed.Weakening R as W hiding (wk)

open import Tools.Fin
open import Tools.Function
open import Tools.Product
import Tools.PropositionalEquality as PE
open import Tools.Reasoning.PropositionalEquality

private variable
                                           : DCon _ _
  Δ₁ Δ₂                                     : Con _ _
  Γ                                         : Cons _ _
  A₁ A₂ B₁ B₂ C₁ C₂ t₁ t₂ u₁ u₂ v₁ v₂ w₁ w₂ : Term _
  p                                         : M

opaque
  unfolding subst

  -- An equality rule for subst.

  subst-cong :
    Γ  A₁ 
    Γ  A₁  A₂ 
    Γ »∙ A₁  B₁  B₂ 
    Γ  t₁  A₁ 
    Γ  t₁  t₂  A₁ 
    Γ  u₁  u₂  A₁ 
    Γ  v₁  v₂  Id A₁ t₁ u₁ 
    Γ  w₁  w₂  B₁ [ t₁ ]₀ 
    Γ  subst p A₁ B₁ t₁ u₁ v₁ w₁  subst p A₂ B₂ t₂ u₂ v₂ w₂ 
      B₁ [ u₁ ]₀
  subst-cong {B₁} ⊢A₁ A₁≡A₂ B₁≡B₂ ⊢t₁ t₁≡t₂ u₁≡u₂ v₁≡v₂ w₁≡w₂ =
    PE.subst (_⊢_≡_∷_ _ _ _) (subst-wk B₁) $
    J-cong A₁≡A₂ ⊢t₁ t₁≡t₂
      (wk₁ (Idⱼ (wk₁ ⊢A₁ ⊢A₁) (wk₁ ⊢A₁ ⊢t₁) (var₀ ⊢A₁)) B₁≡B₂)
      (PE.subst (_⊢_≡_∷_ _ _ _) (PE.sym $ subst-wk B₁) w₁≡w₂) u₁≡u₂
      v₁≡v₂

opaque
  unfolding Quot-rel-Con

  -- A congruence lemma for Quot-rel-Con.

  Quot-rel-Con-cong :
     »⊢ Δ₁  Δ₂ 
     » Δ₂  A₂ 
     » Δ₁  A₁  A₂ 
     »⊢ Quot-rel-Con Δ₁ A₁  Quot-rel-Con Δ₂ A₂
  Quot-rel-Con-cong Δ₁≡Δ₂ ⊢A₂ A₁≡A₂ =
    let A₁≡A₂ = stability-⊢ Δ₁≡Δ₂ A₁≡A₂ in
    Δ₁≡Δ₂ ∙⟨ ⊢A₂  A₁≡A₂  ∙⟨ wk₁ ⊢A₂ ⊢A₂  wk₁ ⊢A₂ A₁≡A₂ 

opaque
  unfolding Resp-Con

  -- A congruence lemma for Resp-Con.

  Resp-Con-cong :
     »⊢ Δ₁  Δ₂ 
     » Δ₂  A₂ 
     » Δ₁  A₁  A₂ 
     » Quot-rel-Con Δ₂ A₂  B₂ 
     » Quot-rel-Con Δ₁ A₁  B₁  B₂ 
     »⊢ Resp-Con Δ₁ A₁ B₁  Resp-Con Δ₂ A₂ B₂
  Resp-Con-cong Δ₁≡Δ₂ ⊢A₂ A₁≡A₂ ⊢B₂ B₁≡B₂ =
    let Eq = Quot-rel-Con-cong Δ₁≡Δ₂ ⊢A₂ A₁≡A₂ in
    Eq ∙⟨ ⊢B₂  stability-⊢ Eq B₁≡B₂ 

opaque
  unfolding Quot-rel-Con Resp-Con Resp-type

  -- A congruence lemma for Resp-type.

  Resp-type-cong :
    Γ  A₁  A₂ 
    Quot-rel-Cons Γ A₁  B₁ 
    Quot-rel-Cons Γ A₁  B₁  B₂ 
    Γ »∙ Quot A₁ B₁  C₁  C₂ 
    Γ »∙ A₁  t₁  t₂  C₁ [ class (var x0) ]↑ 
    Resp-Cons Γ A₁ B₁  Resp-type A₁ B₁ C₁ t₁  Resp-type A₂ B₂ C₂ t₂
  Resp-type-cong {B₁} {C₁} A₁≡A₂ ⊢B₁ B₁≡B₂ C₁≡C₂ t₁≡t₂ =
    let ⊢Q₁          = ⊢∙→⊢ (wf C₁≡C₂)
        ok , ⊢A₁ , _ = inversion-Quot ⊢Q₁
        ΓA₁A₁B₁⊇ΓA₁  = ʷ⊇-drop ( ⊢B₁)
        ⊢Q₁′         = W.wk ΓA₁A₁B₁⊇ΓA₁ ⊢Q₁
        ⊢1           = PE.subst (_⊢_∷_ _ _) wk[]≡wk[]′ (var₁ ⊢B₁)
        ⊢class-2     = class ⊢Q₁′ (var₂′ ⊢B₁)
    in
    Id-cong
      (subst-⊢≡ C₁≡C₂ $ refl-⊢ˢʷ≡∷ $ ⊢ˢʷ∷-[][]↑ $
       PE.subst (_⊢_∷_ _ _) (PE.sym wk[]≡wk[]′) $
       class ⊢Q₁′
         (PE.subst (_⊢_∷_ _ _) wk[]≡wk[]′ $
          var₁ ⊢B₁))
      (PE.subst (_⊢_≡_∷_ _ _ _) ([][]↑-[] 4 C₁) $
       subst-cong ⊢Q₁′
         (W.wk ΓA₁A₁B₁⊇ΓA₁ (Quot-cong ok A₁≡A₂ B₁≡B₂))
         (subst-⊢≡ C₁≡C₂ $ refl-⊢ˢʷ≡∷ $ ⊢ˢʷ∷-[][]↑ $
          PE.subst (_⊢_∷_ _ _)
            (PE.trans (wk-comp _ _ _) (PE.sym wk[]≡wk[]′)) $
          var₀ ⊢Q₁′)
         ⊢class-2
         (refl ⊢class-2)
         (refl (class ⊢Q₁′ ⊢1))
         (resp-cong ok (W.wk (ʷ⊇-drop ( ⊢B₁)) A₁≡A₂)
            (W.wk
               (PE.subst₄ _»_∷ʷ_⊇_ PE.refl PE.refl
                  (PE.cong (_∙_ _)
                     (PE.trans (wk-comp _ _ _) $
                      PE.sym (wk-comp _ _ _)))
                  PE.refl $
                 liftⁿʷ {k = 2} (⊇-drop {k = 3})
                   (∙_ $ PE.subst (_⊢_ _) (PE.sym (wk-comp _ _ _)) $
                    W.wk (ʷ⊇-drop ( W.wk (ʷ⊇-drop ( ⊢B₁)) ⊢A₁)) ⊢A₁))
               B₁≡B₂)
            (refl (var₂′ ⊢B₁)) (refl ⊢1)
            (refl $
             PE.subst (_⊢_∷_ _ _)
               (wk1 B₁                                                    ≡⟨ wk-liftn 0 

                B₁ [ wkSubst 1 idSubst ]                                  ≡⟨ (flip substVar-to-subst B₁ λ where
                                                                                x0         PE.refl
                                                                                (x0 +1)    PE.refl
                                                                                (_ +1 +1)  PE.refl) 
                B₁
                  [ consSubst
                      (consSubst (toSubst (stepn id 3)) (var x2))
                      (var x1)
                  ]                                                       ≡˘⟨ doubleSubstComp B₁ _ _ _ 

                B₁ [ toSubst (stepn id 3) ⇑[ 2 ] ] [ var x2 , var x1 ]₁₀  ≡˘⟨ PE.cong _[ _ , _ ]₁₀ (wk-liftn 2 {t = B₁}) 

                wk (liftn (stepn id 3) 2) B₁ [ var x2 , var x1 ]₁₀        ) $
             var₀ ⊢B₁))
         (PE.subst (_⊢_≡_∷_ _ _ _)
            (wk[ 2 ]′ (C₁ [ class (var x0) ]↑)        ≡⟨ wk[]′[][]↑ 2 C₁ 
             C₁ [ 3 ][ wk[ 2 ]′ (class (var x0)) ]↑   ≡˘⟨ [][]↑-[] 4 C₁ 
             C₁ [ 4 ][ var x0 ]↑ [ class (var x2) ]₀  ) $
          W.wk (ʷ⊇-drop ( ⊢B₁)) t₁≡t₂))
      (PE.subst (_⊢_≡_∷_ _ _ _) ([][]↑-[] 1 C₁) $
       subst-⊢≡ t₁≡t₂ (refl-⊢ˢʷ≡∷ (⊢ˢʷ∷-[][]↑ (var₁ ⊢B₁))))

opaque
  unfolding Is-set-Con

  -- A congruence lemma for Is-set-Con.

  Is-set-Con-cong :
     »⊢ Δ₁  Δ₂ 
     » Δ₁  A₁  A₂ 
     » Quot-rel-Con Δ₁ A₁  B₁  B₂ 
     » Δ₂  Quot A₂ B₂  C₂ 
     » Δ₁  Quot A₁ B₁  C₁  C₂ 
     »⊢ Is-set-Con Δ₁ A₁ B₁ C₁  Is-set-Con Δ₂ A₂ B₂ C₂
  Is-set-Con-cong Δ₁≡Δ₂ A₁≡A₂ B₁≡B₂ ⊢C₂ C₁≡C₂ =
    let ok , _ , ⊢B₂ = inversion-Quot (⊢∙→⊢ (wf ⊢C₂))
        Eq₁          = Δ₁≡Δ₂ ∙⟨ Quot ok ⊢B₂
                               stability-⊢ Δ₁≡Δ₂
                                  (Quot-cong ok A₁≡A₂ B₁≡B₂)
                              
        Eq₂          = Eq₁ ∙⟨ ⊢C₂  stability-⊢ Eq₁ C₁≡C₂ 
        ⊢C₂′         = wk₁ ⊢C₂ ⊢C₂
        Eq₃          = Eq₂ ∙⟨ ⊢C₂′  wk₁ ⊢C₂ (stability-⊢ Eq₁ C₁≡C₂) 
        ⊢Id-1-0      = Idⱼ (W.wk (ʷ⊇-drop ( ⊢C₂′)) ⊢C₂) (var₁′ ⊢C₂′)
                         (PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
                          var₀ ⊢C₂′)
        Eq₄          = Eq₃
                         ∙⟨ ⊢Id-1-0
                           _⊢_≡_.sym $
                            Id-cong
                              (_⊢_≡_.sym $
                               W.wk (ʷ⊇-drop ( ⊢C₂′))
                                 (stability-⊢ Eq₁ C₁≡C₂))
                              (refl (var₁′ ⊢C₂′))
                              (_⊢_≡_∷_.refl $
                               PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
                               var₀ ⊢C₂′)
                          
    in
    Eq₄
      ∙⟨ Idⱼ (W.wk (ʷ⊇-drop ( ⊢Id-1-0)) ⊢C₂) (var₂′ ⊢Id-1-0)
           (PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
            var₁′ ⊢Id-1-0)
        _⊢_≡_.sym $
         Id-cong
           (sym (W.wk (ʷ⊇-drop ( ⊢Id-1-0)) (stability-⊢ Eq₁ C₁≡C₂)))
           (refl (var₂′ ⊢Id-1-0))
           (_⊢_≡_∷_.refl $
            PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
            var₁′ ⊢Id-1-0)
       

opaque
  unfolding Is-set-Con Is-set-type

  -- A congruence lemma for Is-set-type.

  Is-set-type-cong :
    Γ »∙ Quot A₁ B₁  C₁ 
    Γ »∙ Quot A₁ B₁  C₁  C₂ 
    Is-set-Cons Γ A₁ B₁ C₁  Is-set-type C₁  Is-set-type C₂
  Is-set-type-cong ⊢C₁ C₁≡C₂ =
    let ⊢C₁′    = wk₁ ⊢C₁ ⊢C₁
        ⊢Id-1-0 =
          Idⱼ (W.wk (ʷ⊇-drop ( ⊢C₁′)) ⊢C₁)
            (var₁′ ⊢C₁′)
            (PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
             var₀ ⊢C₁′)
        ⊢Id-2-1 =
          Idⱼ (W.wk (ʷ⊇-drop ( ⊢Id-1-0)) ⊢C₁)
            (var₂′ ⊢Id-1-0)
            (PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
             var₁′ ⊢Id-1-0)
    in
    Id-cong
      (Id-cong (W.wk (ʷ⊇-drop ( ⊢Id-2-1)) C₁≡C₂)
         (_⊢_≡_∷_.refl $
          var₃′ ⊢Id-2-1)
         (_⊢_≡_∷_.refl $
          PE.subst (_⊢_∷_ _ _) (wk-comp _ _ _) $
          var₂′ ⊢Id-2-1))
      (_⊢_≡_∷_.refl $
       PE.subst (_⊢_∷_ _ _)
         (PE.cong₃ Id (wk-comp _ _ _) PE.refl PE.refl) $
       var₁′ ⊢Id-2-1)
      (_⊢_≡_∷_.refl $
       PE.subst (_⊢_∷_ _ _)
         (PE.cong₃ Id (wk-comp _ _ _) PE.refl PE.refl) $
       var₀ ⊢Id-2-1)