open import Data.Empty
open import Data.List 
open import Data.Product
open import Data.Sum
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality as PEq 
open import Data.List.Membership.Propositional
open import Data.List.Relation.Unary.Any
open import Data.List.Relation.Binary.Subset.Propositional
open import Data.List.Relation.Binary.Subset.Propositional.Properties
open import Data.Nat hiding (_≟_)
open import Relation.Binary.Construct.Closure.ReflexiveTransitive
import Relation.Binary.Reasoning.Preorder as PreR

open import Stoughton.Var
 
module PTS.ClosureSub {𝒞 𝒱 : Set} (isVar : Enum 𝒱) (𝒜 : 𝒞 → 𝒞 → Set) (ℛ : 𝒞 → 𝒞 → 𝒞 → Set) where

  private
    _≟_ = Enum._≟_ isVar
    
  open import PTS isVar 𝒜 ℛ
  open import PTS.Thinning isVar 𝒜 ℛ
  open import PTS.ClosureAlpha isVar 𝒜 ℛ
  open import PTS.SyntacticValidity isVar 𝒜 ℛ
  
  open import Stoughton.Alpha 𝒞 isVar
  open import Beta 𝒞 isVar
  open import Stoughton.Chi (Enum.encode isVar) (Enum.decode isVar) (Enum.inverse isVar)
  open import Stoughton.Substitution 𝒞 isVar
  open import Stoughton.SubstitutionLemmas 𝒞 isVar
  open import Stoughton.Syntax 𝒞 𝒱 _≟_ hiding (length)
  open import Context 𝒱 Λ _≟_
  open import Context.Properties 𝒞 isVar  
  open import BetaConversion 𝒞 isVar
  
  open PreR ≈-preorder∼

  infix 2 _∶_⇀_
  _∶_⇀_ : Sub → Cxt → Cxt → Set
  σ ∶ Γ ⇀ Δ = ∀ {x A} → (x , A) ∈ Γ → Δ ⊢ σ x ∶ A ∙ σ

  subRen : ∀ {Γ Δ x y s s' A σ} → x ∉ dom Γ → y ∉ dom Δ → Γ ⊢ A ∶ c s → Δ ⊢ A ∙ σ ∶ c s' → σ ∶ Γ ⇀ Δ
         → (σ ‚ x := v y) ∶ (Γ ‚ x ∶ A) ⇀ (Δ ‚ y ∶ A ∙ σ)
  subRen {Γ} {Δ} {x} {y} {s} {s'} {A} {σ} x∉domΓ y∉domΔ Γ⊢A:s Δ⊢Aσ:s' h = lemma2
    where
    Δok : Δ ok
    Δok = validCxt Δ⊢Aσ:s'
    Δ,y:Aσok : Δ ‚ y ∶ A ∙ σ ok
    Δ,y:Aσok = ⊢cons Δok y∉domΔ Δ⊢Aσ:s'
    lemma2 : ∀ {z B} → (z , B) ∈ (Γ ‚ x ∶ A) → Δ ‚ y ∶ A ∙ σ ⊢ (σ ‚ x := v y) z ∶ B ∙ σ ‚ x := v y
    lemma2 {z} {B} _ with x ≟ z
    lemma2 {.x} {.A} (here refl) | yes refl = subst (_⊢_∶_ (Δ ‚ y ∶ A ∙ σ) (v y)) Aσ=Aσ<+x,y Δ,y:Aσ⊢y:Aσ
      where      
      x#A : x # A 
      x#A = c∉xs++ys→c∉xs (freshAsg x∉domΓ Γ⊢A:s)
      Aσ=Aσ<+x,y : A ∙ σ ≡ A ∙ σ ‚ x := v y
      Aσ=Aσ<+x,y = sym (updFresh {x} {A} x#A)
      Δ,y:Aσ⊢y:Aσ : Δ ‚ y ∶ A ∙ σ ⊢ v y ∶ A ∙ σ
      Δ,y:Aσ⊢y:Aσ = ⊢var Δ,y:Aσok (here refl)
    lemma2 {.x} {B} (there x,B∈Γ) | yes refl = ⊥-elim (x∉domΓ (inCxtInDom x,B∈Γ))
    lemma2 {.x} {.A} (here refl) | no x≢x = ⊥-elim (x≢x refl)
    lemma2 {z} {B} (there z,B∈Γ) | no _ = subst (_⊢_∶_ (Δ ‚ y ∶ A ∙ σ) (σ z)) Bσ=Bσ<+x,y Δ,y:Aσ⊢σz:Bσ
      where
      Δ⊆Δ,y:A : Δ ⊆ (Δ ‚ y ∶ A ∙ σ)
      Δ⊆Δ,y:A = xs⊆x∷xs Δ (y , A ∙ σ)
      Γok : Γ ok
      Γok = validCxt Γ⊢A:s
      x#B : x # B
      x#B = freshCxt Γok x∉domΓ z,B∈Γ
      Bσ=Bσ<+x,y : B ∙ σ ≡ B ∙ σ ‚ x := v y
      Bσ=Bσ<+x,y = sym (updFresh {x} {B} x#B)
      Δ⊢σz:Bσ : Δ ⊢ σ z ∶ B ∙ σ
      Δ⊢σz:Bσ = h z,B∈Γ
      Δ,y:Aσ⊢σz:Bσ : Δ ‚ y ∶ A ∙ σ ⊢ σ z ∶ B ∙ σ
      Δ,y:Aσ⊢σz:Bσ = thinning Δ⊆Δ,y:A Δ,y:Aσok Δ⊢σz:Bσ      

  closureSub : ∀ {Γ Δ M A σ} → σ ∶ Γ ⇀ Δ → Δ ok → Γ ⊢ M ∶ A → Δ ⊢ M ∙ σ ∶ A ∙ σ
  closureSub _ Δok (⊢sort _ As₁s₂) = ⊢sort Δok As₁s₂
  closureSub sub _ (⊢var _ x,A∈Γ) = sub x,A∈Γ
  closureSub {Γ} {Δ} {_} {_} {σ} sub Δok Γ⊢λ[x:A]M:Π[y:A]B@(⊢abs {x} {y} {s₁} {s₂} {s₃} {A} {B} {M} Rs₁s₂s₃ Γ⊢A:s₁ h h₀) =
    ⊢abs Rs₁s₂s₃ Δ⊢Aσ:s₁ goal goal₀
    where
    x' y' : 𝒱    
    x' = X (σ , fv M - x)
    y' = X (σ , fv B - y)
    x'#σ⇂fvM-x : x' #⇂ (σ , fv M - x)
    x'#σ⇂fvM-x = Xfresh σ (fv M - x)
    y'#σ⇂fvB-y : y' #⇂ (σ , fv B - y)
    y'#σ⇂fvB-y = Xfresh σ (fv B - y)
    Δ⊢Aσ:s₁ : Δ ⊢ A ∙ σ ∶ c s₁
    Δ⊢Aσ:s₁ = closureSub sub Δok Γ⊢A:s₁
    goal : ∀ z → z ∉ dom Δ → Δ ‚ z ∶ A ∙ σ ⊢ (M ∙ σ ‚ x := v x') [ x' := v z ] ∶ (B ∙ σ ‚ y := v y') [ y' := v z ]
    goal z z∉domΔ =
      closureAlpha ∼ρs lemma1 lemma2 ih
      where
      z' : 𝒱
      z' = X' (dom Γ)
      z'∉domΓ : z' ∉ dom Γ
      z'∉domΓ = Xpfresh (dom Γ)
      sub' : σ ‚ z' := v z ∶ (Γ ‚ z' ∶ A) ⇀ Δ ‚ z ∶ A ∙ σ 
      sub' = subRen z'∉domΓ z∉domΔ Γ⊢A:s₁ Δ⊢Aσ:s₁ sub
      Δ,z:Aσok : Δ ‚ z ∶ A ∙ σ ok
      Δ,z:Aσok = ⊢cons Δok z∉domΔ Δ⊢Aσ:s₁
      ih : Δ  ‚ z ∶ A ∙ σ ⊢ M [ x := v z' ] ∙ σ ‚ z' := v z ∶ B [ y := v z' ] ∙ σ ‚ z' := v z
      ih = closureSub sub' Δ,z:Aσok (h z' z'∉domΓ)
      lemma1 : M [ x := v z' ] ∙ σ ‚ z' := v z ∼α (M ∙ σ ‚ x := v x') [ x' := v z ]
      lemma1 = 
        begin
        M [ x := v z' ] ∙ σ ‚ z' := v z
        ≈⟨ sym (composRenUpd {x} {z'} {M} {v z} z'∉fvM-x) ⟩
        M ∙ σ ‚ x := v z
        ∼⟨ ∼σ (composRenUnary {x} {x'} {σ} {M} x'#σ⇂fvM-x) ⟩
        (M ∙ σ ‚ x := v x') [ x' := v z ]
        ∎
        where
        z'∉fvM-x : z' ∉ fv M - x
        z'∉fvM-x = c∉xs++ys→c∉ys {xs = fv A} (c∉xs++ys→c∉xs (freshAsg z'∉domΓ Γ⊢λ[x:A]M:Π[y:A]B))              
      lemma2 : B [ y := v z' ] ∙ σ ‚ z' := v z ∼α (B ∙ σ ‚ y := v y') [ y' := v z ]
      lemma2 = 
        begin
        B [ y := v z' ] ∙ σ ‚ z' := v z
        ≈⟨ sym (composRenUpd {y} {z'} {B} {v z} z'∉fvB-y) ⟩
        B ∙ σ ‚ y := v z
        ∼⟨ ∼σ (composRenUnary {y} {y'} {σ} {B} y'#σ⇂fvB-y) ⟩
        (B ∙ σ ‚ y := v y') [ y' := v z ]
        ∎
        where
        z'∉fvB-y : z' ∉ fv B - y
        z'∉fvB-y = c∉xs++ys→c∉ys {xs = fv A} (c∉xs++ys→c∉ys {xs = fv A ++ (fv M - x)} (freshAsg z'∉domΓ Γ⊢λ[x:A]M:Π[y:A]B))
    goal₀ : ∀ z → z ∉ dom Δ → Δ ‚ z ∶ A ∙ σ ⊢ (B ∙ σ ‚ y := v y') [ y' := v z ] ∶ c s₂
    goal₀ z z∉domΔ =
      closureAlpha ∼ρs lemma2 ∼ρ ih
      where
      z' : 𝒱
      z' = X' (dom Γ)
      z'∉domΓ : z' ∉ dom Γ
      z'∉domΓ = Xpfresh (dom Γ)
      sub' : σ ‚ z' := v z ∶ (Γ ‚ z' ∶ A) ⇀ Δ ‚ z ∶ A ∙ σ 
      sub' = subRen z'∉domΓ z∉domΔ Γ⊢A:s₁ Δ⊢Aσ:s₁ sub
      Δ,z:Aσok : Δ ‚ z ∶ A ∙ σ ok
      Δ,z:Aσok = ⊢cons Δok z∉domΔ Δ⊢Aσ:s₁
      ih : Δ  ‚ z ∶ A ∙ σ ⊢ B [ y := v z' ] ∙ σ ‚ z' := v z ∶ c s₂
      ih = closureSub sub' Δ,z:Aσok (h₀ z' z'∉domΓ)
      lemma2 : B [ y := v z' ] ∙ σ ‚ z' := v z ∼α (B ∙ σ ‚ y := v y') [ y' := v z ]
      lemma2 = 
        begin
        B [ y := v z' ] ∙ σ ‚ z' := v z
        ≈⟨ sym (composRenUpd {y} {z'} {B} {v z} z'∉fvB-y) ⟩
        B ∙ σ ‚ y := v z
        ∼⟨ ∼σ (composRenUnary {y} {y'} {σ} {B} y'#σ⇂fvB-y) ⟩
        (B ∙ σ ‚ y := v y') [ y' := v z ]
        ∎
        where
        z'∉fvB-y : z' ∉ fv B - y
        z'∉fvB-y = c∉xs++ys→c∉ys {xs = fv A} (c∉xs++ys→c∉ys {xs = fv A ++ (fv M - x)} (freshAsg z'∉domΓ Γ⊢λ[x:A]M:Π[y:A]B))           
  closureSub {Γ} {Δ} {_} {_} {σ} sub Δok (⊢app {x} {s} {M} {N} {A} {B} Γ⊢M:ΠxAB Γ⊢N:A Γ⊢[N/x]B:s) =
    closureAlpha ∼ρs ∼ρ (∼σ lemma) Δ⊢σMσN:[σN/x']x'/x,σB 
    where
    x' : 𝒱
    x' = X (σ , fv B - x)
    x'#σ⇂fvB-x : x' #⇂ (σ , fv B - x)
    x'#σ⇂fvB-x = Xfresh σ (fv B - x)
    Δ⊢σM:Π[x:Aσ]x'/x,σB : Δ ⊢ M ∙ σ ∶ Π[ x' ∶ A ∙ σ ] (B ∙ σ ‚ x := v x') 
    Δ⊢σM:Π[x:Aσ]x'/x,σB = closureSub sub Δok Γ⊢M:ΠxAB
    Δ⊢σN:σA : Δ ⊢ N ∙ σ ∶ A ∙ σ 
    Δ⊢σN:σA = closureSub sub Δok Γ⊢N:A
    Δ⊢σ[N/x]B:s : Δ ⊢ B [ x := N ] ∙ σ ∶ c s
    Δ⊢σ[N/x]B:s = closureSub sub Δok Γ⊢[N/x]B:s
    lemma : B [ x := N ] ∙ σ ∼α (B ∙ σ ‚ x := v x') [ x' := N ∙ σ ] 
    lemma = 
      begin 
      B [ x := N ] ∙ σ
      ≈⟨ sym (subDistribUpd {B} {N} {σ} {x}) ⟩
      B ∙ σ ‚ x := (N ∙ σ)
      ∼⟨ ∼σ (composRenUnary {x} {x'} {σ} {B} {N ∙ σ} x'#σ⇂fvB-x) ⟩
      (B ∙ σ ‚ x := v x') [ x' := N ∙ σ ] 
      ∎ 
    Δ⊢σMσN:[σN/x']x'/x,σB : Δ ⊢ (M · N) ∙ σ ∶ (B ∙ σ ‚ x := v x') [ x' := N ∙ σ ]
    Δ⊢σMσN:[σN/x']x'/x,σB = ⊢app Δ⊢σM:Π[x:Aσ]x'/x,σB Δ⊢σN:σA (closAlphaAsg ∼ρs lemma Δ⊢σ[N/x]B:s)
  closureSub sub Δok (⊢conv Γ⊢M:A A=B Γ⊢B:s) = ⊢conv (closureSub sub Δok Γ⊢M:A) (compatConvSub A=B) (closureSub sub Δok Γ⊢B:s)
  closureSub {Γ} {Δ} {_} {_} {σ} sub Δok Γ⊢Π[y:A]B:𝒰@(⊢prod {y} {s₁} {s₂} {s₃} {A} {B} Rs₁s₂s₃ Γ⊢A:s₁ h) = ⊢prod Rs₁s₂s₃ Δ⊢Aσ:s₁ goal
    where
    y' : 𝒱
    y' = X (σ , fv B - y)
    y'#σ⇂fvB-y : y' #⇂ (σ , fv B - y)
    y'#σ⇂fvB-y = Xfresh σ (fv B - y)  
    Δ⊢Aσ:s₁ : Δ ⊢ A ∙ σ ∶ c s₁
    Δ⊢Aσ:s₁ = closureSub sub Δok Γ⊢A:s₁
    goal : ∀ z → z ∉ dom Δ → Δ ‚ z ∶ A ∙ σ ⊢ (B ∙ σ ‚ y := v y') [ y' := v z ] ∶ c s₂
    goal z z∉domΔ = closAlphaAsg ∼ρs lemma ih
      where
      z' : 𝒱
      z' = X' (dom Γ)
      z'∉domΓ : z' ∉ dom Γ
      z'∉domΓ = Xpfresh (dom Γ)
      z'∉fvB-y : z' ∉ fv B - y
      z'∉fvB-y = c∉xs++ys→c∉ys {xs = fv A} (c∉xs++ys→c∉xs (freshAsg z'∉domΓ Γ⊢Π[y:A]B:𝒰))
      sub' : σ ‚ z' := v z ∶ (Γ ‚ z' ∶ A) ⇀ Δ ‚ z ∶ A ∙ σ 
      sub' = subRen z'∉domΓ z∉domΔ Γ⊢A:s₁ Δ⊢Aσ:s₁ sub
      Δ,z:Aσok : Δ ‚ z ∶ A ∙ σ ok
      Δ,z:Aσok = ⊢cons Δok z∉domΔ Δ⊢Aσ:s₁
      ih : Δ ‚ z ∶ A ∙ σ ⊢ B [ y := v z' ] ∙ σ ‚ z' := v z ∶ c s₂
      ih = closureSub sub' Δ,z:Aσok (h z' z'∉domΓ)         
      lemma : B [ y := v z' ] ∙ σ ‚ z' := v z ∼α (B ∙ σ ‚ y := v y') [ y' := v z ]
      lemma = 
        begin
        B [ y := v z' ] ∙ σ ‚ z' := v z
        ≈⟨ sym (composRenUpd {y} {z'} {B} {v z} z'∉fvB-y) ⟩
        B ∙ σ ‚ y := v z
        ∼⟨ ∼σ (composRenUnary {y} {y'} {σ} {B} y'#σ⇂fvB-y) ⟩
        (B ∙ σ ‚ y := v y') [ y' := v z ]
        ∎ 

  infixl 6 _∙∙_ 
  _∙∙_ : Cxt → Sub → Cxt
  [] ∙∙ _ = []
  ((x , A) ∷ Γ) ∙∙ σ = (x , A ∙ σ) ∷ (Γ ∙∙ σ)

  subDistribDecl : ∀ {Γ x A σ} → (x , A) ∈ Γ → (x , A ∙ σ) ∈ (Γ ∙∙ σ) 
  subDistribDecl (here refl) = here refl
  subDistribDecl (there x,A∈Γ) = there (subDistribDecl x,A∈Γ)

  open import Data.List.Relation.Binary.Pointwise as PW

  lemma∙∙ι : ∀ {Γ} → Γ ≈α Γ ∙∙ ι
  lemma∙∙ι {[]} = []
  lemma∙∙ι {(x , A) ∷ Γ} = (PEq.refl , lemma∙ι) ∷ lemma∙∙ι {Γ}

  subUnaryAux : ∀ {x s Γ N A} → x ∉ dom Γ → Γ ⊢ A ∶ s → Γ ∙∙ ι ⊢ N ∶ A ∙ ι → ι ‚ x := N ∶ (Γ ‚ x ∶ A) ⇀ Γ ∙∙ ι
  subUnaryAux {x} x∉domΓ Γ⊢A:𝒰 Γι⊢N:Aι {y} y∈domΓ,x:Aι with x ≟ y
  subUnaryAux {x} {s} {Γ} {N} {A} x∉domΓ Γ⊢A:s Γι⊢N:Aι {.x} (here refl) | yes refl = subst (_⊢_∶_ (Γ ∙∙ ι) N) Aι=Aι<+x,N Γι⊢N:Aι
    where
    x#A : x # A
    x#A = c∉xs++ys→c∉xs (freshAsg x∉domΓ Γ⊢A:s)
    Aι=Aι<+x,N : A ∙ ι ≡ A ∙ ι ‚ x := N
    Aι=Aι<+x,N = sym (updFresh {x} {A} x#A)
  subUnaryAux {x} x∉domΓ _ _ {.x} (there x,B∈Γ) | yes refl = ⊥-elim (x∉domΓ (inCxtInDom x,B∈Γ))
  subUnaryAux {x} {Γ} {N} {A} _ _ _ {.x} (here refl) | no x≠x = ⊥-elim (x≠x PEq.refl)
  subUnaryAux {x} {s} {Γ} {N} {A} x∉domΓ Γ⊢A:s Γι⊢N:Aι {y} {B} (there y,B∈Γ) | no _ = subst (_⊢_∶_ (Γ ∙∙ ι) (v y)) Bι=[N/x]B ιΓ⊢y:ιB
    where
    Γok : Γ ok
    Γok = validCxt Γ⊢A:s
    Γιok : Γ ∙∙ ι ok
    Γιok = validCxt Γι⊢N:Aι
    x#B : x # B
    x#B = freshCxt Γok x∉domΓ y,B∈Γ
    Bι=[N/x]B : B ∙ ι ≡ B ∙ ι ‚ x := N
    Bι=[N/x]B = sym (updFresh {x} {B} x#B)
    y,Bι∈Γι : (y , B ∙ ι) ∈ (Γ ∙∙ ι)
    y,Bι∈Γι = subDistribDecl y,B∈Γ
    ιΓ⊢y:ιB : Γ ∙∙ ι ⊢ v y ∶ B ∙ ι
    ιΓ⊢y:ιB = ⊢var Γιok y,Bι∈Γι

  subUnary : ∀ {x s Γ N A} → x ∉ dom Γ → Γ ⊢ A ∶ s → Γ ⊢ N ∶ A → (ι ‚ x := N) ∶ (Γ ‚ x ∶ A) ⇀ Γ
  subUnary {x} {s} {Γ} {N} {A} x∉domΓ Γ⊢A:s Γ⊢N:A {z} {B} z,B∈Γ =
    closAlphaAsg (∼σs lemma∙∙ι) ∼ρ Γι⊢z[x=N]:A[x=N] 
    where
    ιΓ⊢N:ιA : Γ ∙∙ ι ⊢ N ∶ A ∙ ι
    ιΓ⊢N:ιA = closAlphaPred lemma∙∙ι lemma∙ι Γ⊢N:A
    ιΓok : Γ ∙∙ ι ok
    ιΓok = validCxt ιΓ⊢N:ιA
    ι,x=N:Γ,x:A→Γι : ι ‚ x := N ∶ (Γ ‚ x ∶ A) ⇀ Γ ∙∙ ι
    ι,x=N:Γ,x:A→Γι = subUnaryAux x∉domΓ Γ⊢A:s ιΓ⊢N:ιA
    Γι⊢z[x=N]:A[x=N] : Γ ∙∙ ι ⊢ (ι ‚ x := N) z ∶ B ∙ ι ‚ x := N
    Γι⊢z[x=N]:A[x=N] = ι,x=N:Γ,x:A→Γι z,B∈Γ

  cut :  ∀ {Γ M N A B x} → Γ ‚ x ∶ A ⊢ M ∶ B → Γ ⊢ N ∶ A → Γ ⊢ M [ x := N ] ∶ B [ x := N ]
  cut {Γ} {M} {N} {A} {B} {x} Γ,x:A⊢M:B Γ⊢N:A with syntacticValidity Γ⊢N:A
  cut {Γ} {M} {N} {.(c s)} {B} {x} Γ,x:s⊢M:B Γ⊢N:s | s , inj₁ refl =
    closureSub ι,x=N:Γ,x:s→Γ Γok Γ,x:s⊢M:B
    where
    x∉domΓ : x ∉ dom Γ
    x∉domΓ with validCxt Γ,x:s⊢M:B
    ... | ⊢cons _ x∉domΓ _ = x∉domΓ
    Γok : Γ ok
    Γok = validCxt Γ⊢N:s
    Γ⊢s:s' : ∃ λ s' → Γ ⊢ c s ∶ c s'
    Γ⊢s:s' with validCxt Γ,x:s⊢M:B
    ... | ⊢cons {s = s'} _ _ Γ⊢s:s' = s' , Γ⊢s:s'
    ι,x=N:Γ,x:s→Γ : ι ‚ x := N ∶ (Γ ‚ x ∶ c s) ⇀ Γ
    ι,x=N:Γ,x:s→Γ = subUnary x∉domΓ (proj₂ Γ⊢s:s') Γ⊢N:s  
  ... | s , inj₂ Γ⊢A:s =
    closureSub ι,x=N:Γ,x:A→Γ Γok Γ,x:A⊢M:B
    where
    x∉domΓ : x ∉ dom Γ
    x∉domΓ with validCxt Γ,x:A⊢M:B
    ... | ⊢cons _ x∉domΓ _ = x∉domΓ
    Γok : Γ ok
    Γok = validCxt Γ⊢N:A
    ι,x=N:Γ,x:A→Γ : ι ‚ x := N ∶ (Γ ‚ x ∶ A) ⇀ Γ
    ι,x=N:Γ,x:A→Γ = subUnary x∉domΓ Γ⊢A:s Γ⊢N:A

  identSub : ∀ {Γ} → Γ ok → ι ∶ Γ ⇀ Γ ∙∙ ι
  identSub {_} Γok {x} x,A∈Γ = closureAlpha lemma∙∙ι ∼ρ lemma∙ι (⊢var Γok x,A∈Γ)

  unaryRen : ∀ {Γ x y A M B} → y ∉ dom Γ → Γ ‚ x ∶ A ⊢ M ∶ B → Γ ‚ y ∶ A ⊢ M [ x := v y ] ∶ B [ x := v y ]
  unaryRen {Γ} {x} {y} {A} {M} {B} y∉domΓ Γ,x:A⊢M:B = closureAlpha Γι,y:Aι∼Γ,y:A ∼ρ ∼ρ Γι,y:Aι⊢M[x=y]:B[x=y]
    where
    Γ,x:Aok : Γ ‚ x ∶ A ok
    Γ,x:Aok = validCxt Γ,x:A⊢M:B
    Γ⊢A:s : ∃ λ s → Γ ⊢ A ∶ c s
    Γ⊢A:s with Γ,x:Aok
    ... | ⊢cons {s = s} _ _ Γ⊢A:s = s , Γ⊢A:s
    x∉domΓ : x ∉ dom Γ
    x∉domΓ with Γ,x:Aok
    ... | ⊢cons _ x∉domΓ _ = x∉domΓ
    y∉domΓι : y ∉ dom (Γ ∙∙ ι)
    y∉domΓι = lemma∉≈α y∉domΓ (∼σs lemma∙∙ι)
    Γι⊢Aι:s : ∃ λ s → Γ ∙∙ ι ⊢ A ∙ ι ∶ c s
    Γι⊢Aι:s = proj₁ Γ⊢A:s , closureAlpha lemma∙∙ι lemma∙ι ∼ρ (proj₂ Γ⊢A:s)
    Γok : Γ ok
    Γok = validCxt (proj₂ Γ⊢A:s)
    Γιok : Γ ∙∙ ι ok
    Γιok = closAlphaCxt lemma∙∙ι Γok
    Γι,y:Aι∼Γ,y:A : Γ ∙∙ ι ‚ y ∶ A ∙ ι ≈α Γ ‚ y ∶ A
    Γι,y:Aι∼Γ,y:A = _∷_ (PEq.refl , (∼σ lemma∙ι)) (∼σs lemma∙∙ι)
    Γι,y:Aιok : Γ ∙∙ ι ‚ y ∶ A ∙ ι ok    
    Γι,y:Aιok =  ⊢cons Γιok y∉domΓι (proj₂ Γι⊢Aι:s)
    ι,x=y:Γ,x:A→Γ,y:Aι : (ι ‚ x := v y) ∶ (Γ ‚ x ∶ A) ⇀ (Γ ‚ y ∶ A) ∙∙ ι
    ι,x=y:Γ,x:A→Γ,y:Aι = subRen x∉domΓ y∉domΓι (proj₂ Γ⊢A:s) (proj₂ Γι⊢Aι:s) (identSub Γok)
    Γι,y:Aι⊢M[x=y]:B[x=y] : Γ ∙∙ ι ‚ y ∶ A ∙ ι ⊢ M [ x := v y ] ∶ B [ x := v y ]
    Γι,y:Aι⊢M[x=y]:B[x=y] = closureSub ι,x=y:Γ,x:A→Γ,y:Aι Γι,y:Aιok Γ,x:A⊢M:B