module Implicit.Algo.Properties.WeakenTVar where

open import Implicit.Language.All
open import Implicit.Algo.Base
open import Implicit.Algo.Properties.Extension
open import Implicit.Algo.Properties.Shift
open import Implicit.Algo.Properties.Id

▶s⨟,-Ω-exist : Γ  Δ ▶s k , T  Γ'  Δ'
             Γ  Ω
             Ω  Δ
             ∃[ Ω' ](Γ  Ω ▶s k , T  Γ'  Ω' ×
                      Ω  Δ ▶s k , T  Ω'  Δ')
▶s⨟,-Ω-exist (▶sS^ new x) (evar ext1) (evar ext2) =  ▶s⨟,-Ω-exist new ext1 ext2 .proj₁ ,^ ,
                                                    ▶sS^ (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₁) x ,
                                                   ▶sS^ (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₂) x 
                                                   
▶s⨟,-Ω-exist (▶sS∙ new x) (uvar ext1) (uvar ext2) =  ▶s⨟,-Ω-exist new ext1 ext2 .proj₁ ,∙ ,
                                                    ▶sS∙ (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₁) x ,
                                                   ▶sS∙ (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₂) x  
▶s⨟,-Ω-exist (▶sS= new x) (svar {A = A} ext1 regA) (svar ext2 regA₁) =  ▶s⨟,-Ω-exist new ext1 ext2 .proj₁ ,= A ,
                                                               ▶sS= (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₁) x ,
                                                              ▶sS= (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₂) x  
▶s⨟,-Ω-exist (▶sS^= new x) (evar ext1) (evar-sol ext2 regA) =  ▶s⨟,-Ω-exist new ext1 ext2 .proj₁ ,^ ,
                                                              ▶sS^ (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₁) x ,
                                                             ▶sS^= (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₂) x 
                                                             
▶s⨟,-Ω-exist (▶sS^= new x) (evar-sol {A = A} ext1 regA) (svar ext2 regA₁) =  ▶s⨟,-Ω-exist new ext1 ext2 .proj₁ ,= A ,
                                                                    ▶sS^= (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₁) x ,
                                                                   ▶sS= (▶s⨟,-Ω-exist new ext1 ext2 .proj₂ .proj₂) x  
▶s⨟,-Ω-exist (▶sS⋈ {Γ' = Γ'} new) (mark regΓ) (mark regΓ₁)
  with refl▶⨟,-unique new =  Γ'  ,  ▶sS⋈ new , ▶sS⋈ new  


ss-weaken, : Γ  A    B  Δ
            Γ  Δ ▶s k , T  Γ'  Δ'
            Γ'  A    B  Δ'

ss-weaken, (s-int regΓ) new with refl▶s⨟,-unique new = s-int (sregular-weaken,s regΓ (▶s⨟,-▶s,-l new))
ss-weaken, (s-var-∙ regΓ x) new with refl▶s⨟,-unique new = s-var-∙ (sregular-weaken,s regΓ (▶s⨟,-▶s,-l new)) (∋∙-weaken,s x (▶s⨟,-▶s,-l new))
ss-weaken, (s-ex-l^ inst) new = s-ex-l^ (inst-weaken,s inst new)
ss-weaken, (s-ex-r^ inst) new = s-ex-r^ (inst-weaken,s inst new)
ss-weaken, (s-ex-l= regΓ x-in) new
  with refl▶s⨟,-unique new = s-ex-l= (sregular-weaken,s regΓ (▶s⨟,-▶s,-l new)) (∋:=-weaken,s x-in (▶s⨟,-▶s,-l new))
ss-weaken, (s-ex-r= regΓ x-in) new
  with refl▶s⨟,-unique new = s-ex-r= (sregular-weaken,s regΓ (▶s⨟,-▶s,-l new)) (∋:=-weaken,s x-in (▶s⨟,-▶s,-l new))
ss-weaken, (s-arr ss ss₁) new
  with  Ω' ,  new1 , new2  ▶s⨟,-Ω-exist new (ss-⊆ ss) (ss-⊆ ss₁)
  = s-arr (ss-weaken, ss new1) (ss-weaken, ss₁ new2)
ss-weaken, {T = T} (s-∀ ss) new
  with  T' , upT ↑ty0-total T = s-∀ (ss-weaken, ss (▶sS∙ new upT))

t-weaken, : Γ  Σ  e  A
           Γ  k , T  Γ'
           Σ ↑tmᶜ k  Σ'
           e ↑tm k  e'
           Γ'  Σ'  e'  A

infs-weaken, : Γ  Σ  A
              Γ  k , T  Γ'
              Σ ↑tmᶜ k  Σ'
              Γ'  Σ'  A
infs-weaken, (infs-z regΓ regA) new ↑tmᶜ-τ = infs-z (tregular-weaken, regΓ new) (⊢r-weaken, regA new)
infs-weaken, (infs-s ⊢e infs) new (↑tmᶜ-e up-e upΣ) = infs-s (t-weaken, ⊢e new ↑tmᶜ-□ up-e) (infs-weaken, infs new upΣ)

s-weaken, : Γ  A ≤⁺ Σ  Δ  B
           Σ ↑tmᶜ k  Σ'
           Γ  Δ ▶s k , T  Γ'  Δ'
           Γ'  A ≤⁺ Σ'  Δ'  B

t-weaken, (⊢lit regΓ) new ↑tmᶜ-□ ↑tm-lit = ⊢lit (tregular-weaken, regΓ new)
t-weaken, (⊢var regΓ x∈Γ) new ↑tmᶜ-□ ↑tm-var = ⊢var (tregular-weaken, regΓ new) (∋⦂-weaken, x∈Γ new)
t-weaken, (⊢ann ⊢e) new ↑tmᶜ-□ (↑tm-⦂ upe) = ⊢ann (t-weaken, ⊢e new ↑tmᶜ-τ upe)
t-weaken, (⊢app ⊢e) new upΣ (↑tm-app upe upe₁) = ⊢app (t-weaken, ⊢e new (↑tmᶜ-e upe₁ upΣ) upe)
t-weaken, (⊢lam₁ ⊢e) new ↑tmᶜ-τ (↑tm-ƛ upe) = ⊢lam₁ (t-weaken, ⊢e (▶S, new) ↑tmᶜ-τ upe)
t-weaken, (⊢lam₂ ⊢e up-c ⊢e₁) new (↑tmᶜ-e {Σ' = Σ'} up-e upΣ) (↑tm-ƛ upe)
  with  Σ″ , upΣ' ↑tmᶜ0-total Σ' = ⊢lam₂ (t-weaken, ⊢e new ↑tmᶜ-□ up-e) upΣ' (t-weaken, ⊢e₁ (▶S, new) (↑tmᶜ-comm' z≤n upΣ upΣ' up-c) upe)
t-weaken, (⊢sub ⊢e ne gc s) new upΣ upe = ⊢sub (t-weaken, ⊢e new ↑tmᶜ-□ upe) (nonempty-↑tmᶜ ne upΣ) (↑tm-gc gc upe) (s-weaken, s upΣ (▶sS⋈ (▶,-▶⨟, new)))
t-weaken, {T = T} (⊢tabs ⊢e) new ↑tmᶜ-□ (↑tm-Λ upe)
  with  T' , upT ↑ty0-total T = ⊢tabs (t-weaken, ⊢e (▶S∙ new upT) ↑tmᶜ-□ upe)
t-weaken, {T = T} (⊢tabs-τ ⊢e) new ↑tmᶜ-τ (↑tm-Λ upe)
  with  T' , upT ↑ty0-total T = ⊢tabs-τ (t-weaken, ⊢e (▶S∙ new upT) ↑tmᶜ-τ upe)
t-weaken, (⊢tapp ⊢e st regA s) new upΣ (↑tm-⓪ upe)
  = ⊢tapp (t-weaken, ⊢e new ↑tmᶜ-□ upe) st (⊢r-weaken, regA new) (s-weaken, s upΣ (▶sS⋈ (▶,-▶⨟, new)))

s-weaken, (s-empty regΓ cloA grd) ↑tmᶜ-□ new
   with refl▶s⨟,-unique new = s-empty (sregular-weaken,s regΓ (▶s⨟,-▶s,-l new)) (⊢c-weaken,s cloA (▶s⨟,-▶s,-l new)) (≫-weaken,s grd (▶s⨟,-▶s,-l new))
s-weaken, (s-type ss) ↑tmᶜ-τ new = s-type (ss-weaken, ss new)
s-weaken, (s-term-c cloA ap ⊢e s) (↑tmᶜ-e up-e upΣ) new = s-term-c (⊢c-weaken,s cloA (▶s⨟,-▶s,-l new))
                                                                   (≫-weaken,s ap (▶s⨟,-▶s,-l new))
                                                                   (t-weaken, ⊢e (▶,-▶s,-𝕣 (▶s⨟,-▶s,-l new)) ↑tmᶜ-τ up-e)
                                                                   (s-weaken, s upΣ new)
s-weaken, (s-term-o opnA ⊢e ss s) (↑tmᶜ-e up-e upΣ) new
  with  Ω' ,  new1 , new2  ▶s⨟,-Ω-exist new (ss-⊆ ss) (s-⊆ s)
  = s-term-o (⊢o-weaken,s opnA (▶s⨟,-▶s,-l new))
             (t-weaken, ⊢e (▶,-▶s,-𝕣 (▶s⨟,-▶s,-l new)) ↑tmᶜ-□ up-e)
             (ss-weaken, ss new1)
             (s-weaken, s upΣ new2)
s-weaken, {T = T} (s-∀l s upᶜ upᵉ upC upD) (↑tmᶜ-e {e' = e'} {Σ' = Σ'} up-e upΣ) new
  with  T' , upT ↑ty0-total T
  with  Σ″ , upΣ' ↑tyᶜ0-total Σ'
  with  e″ , upe' ↑tyᵉ0-total e'
  = s-∀l (s-weaken, s (↑tmᶜ-e (↑tm-↑tyᵉ-comm up-e upe' upᵉ) (↑tmᶜ-↑tyᶜ-comm upΣ upΣ' upᶜ)) (▶sS^= new upT)) upΣ' upe' upC upD
s-weaken, {T = T} (s-∀l-no s upᶜ upᵉ upC upD) (↑tmᶜ-e {e' = e'} {Σ' = Σ'} up-e upΣ) new
  with  T' , upT ↑ty0-total T
  with  Σ″ , upΣ' ↑tyᶜ0-total Σ'
  with  e″ , upe' ↑tyᵉ0-total e'
  = s-∀l-no (s-weaken, s (↑tmᶜ-e (↑tm-↑tyᵉ-comm up-e upe' upᵉ) (↑tmᶜ-↑tyᶜ-comm upΣ upΣ' upᶜ)) (▶sS^ new upT)) upΣ' upe' upC upD
s-weaken, (s-svar-term inΓ s) (↑tmᶜ-e up-e upΣ) new
  with refl▶s⨟,-unique new = s-svar-term (∋:=-weaken,s inΓ (▶s⨟,-▶s,-l new)) (s-weaken, s (↑tmᶜ-e up-e upΣ) new)
s-weaken, (s-evar-infers infs inst) (↑tmᶜ-e up-e upΣ) new = s-evar-infers (infs-weaken, infs (▶,-▶s,-𝕣 (▶s⨟,-▶s,-l new)) (↑tmᶜ-e up-e upΣ)) (inst-weaken,s inst new)

s-weaken,0 : Γ   A ≤⁺ Σ  Δ   B
            ↑tmᶜ0 Σ  Σ'
            Γ ⊢r T
            Γ , T   A ≤⁺ Σ'  Δ , T    B
s-weaken,0 s upΣ regT = s-weaken, s upΣ (▶sS⋈ (▶Z regT))

t-weaken,0 : Γ  Σ  e  A
            ↑tmᶜ0 Σ  Σ'
            ↑tm0 e  e'
            Γ ⊢r T
            Γ , T  Σ'  e'  A
t-weaken,0 ⊢e upΣ upe regT = t-weaken, ⊢e (▶Z regT) upΣ upe