module Implicit.Language.EnvOps.InsertSVar where

open import Implicit.Language.Base
open import Implicit.Language.Shift.All
open import Implicit.Language.Lookup.All
open import Implicit.Language.Regular.All
open import Implicit.Language.OpenClose.Base
open import Implicit.Language.Ground.Base
open import Implicit.Language.EnvOps.Base
open import Implicit.Language.EnvOps.Inst

infix 3 _▶_,=_⇘_
data _▶_,=_⇘_ : Env n m  Fin (1 + m)  Type m  Env n (1 + m)  Set where
  ▶Z  : (regA : Γ ⊢r A)
       Γ  #0 ,= A  Γ ,= A
  ▶S, : Γ  k ,= A  Γ'
       (up : B ↑ty k  B')
       Γ , B  k ,= A  Γ' , B'
  ▶S^ : Γ  k ,= A  Γ'
       ↑ty0 A  A'
       Γ ,^  #S k ,= A'  Γ' ,^
  ▶S∙ : Γ  k ,= A  Γ'
       ↑ty0 A  A'
       Γ ,∙  #S k ,= A'  Γ' ,∙
  ▶S= : Γ  k ,= A  Γ'
       ↑ty0 A  A'
       B ↑ty k  B'
       Γ ,= B  #S k ,= A'  Γ' ,= B'
  ▶S⋈ : Γ  k ,= A  Γ'
       Γ   k ,= A  Γ' 

infix 3 _⨟_▶_,=_⇘_⨟_
data _⨟_▶_,=_⇘_⨟_ : Env n m  Env n m  Fin (1 + m)  Type m  Env n (1 + m)  Env n (1 + m)  Set where
  ▶Z  : (regA : Γ ⊢r A)
       Γ  Δ  #0 ,= A  Γ ,= A  Δ ,= A
  ▶S, : Γ  Δ  k ,= A  Γ'  Δ'
       (up : B ↑ty k  B')
       Γ , B  Δ , B  k ,= A  Γ' , B'  Δ' , B'
  ▶S^ : Γ  Δ  k ,= A  Γ'  Δ'
       ↑ty0 A  A'
       Γ ,^  Δ ,^  #S k ,= A'  Γ' ,^  Δ' ,^
  ▶S^= : Γ  Δ  k ,= A  Γ'  Δ'
        ↑ty0 A  A'
        B ↑ty k  B'
        Γ ,^  Δ ,= B  #S k ,= A'  Γ' ,^  Δ' ,= B'
  ▶S∙ : Γ  Δ  k ,= A  Γ'  Δ'
       ↑ty0 A  A'
       Γ ,∙  Δ ,∙  #S k ,= A'  Γ' ,∙  Δ' ,∙
  ▶S= : Γ  Δ  k ,= A  Γ'  Δ'
       ↑ty0 A  A'
       B ↑ty k  B'
       Γ ,= B  Δ ,= B  #S k ,= A'  Γ' ,= B'  Δ' ,= B'
  ▶S⋈ : Γ  Δ  k ,= A  Γ'  Δ'
       Γ   Δ   k ,= A  Γ'   Δ' 


∋:=-weaken= : Γ  X := A
        Γ  k ,= T  Γ'
        A ↑ty k  A'
        Γ'  punchIn k X := A'
∋:=-weaken= (Z up) (▶Z cloA) upA = S= (Z up) upA
∋:=-weaken= (Z up) (▶S= newΓ x x₁) upA = Z (↑ty-comm0 up upA x₁)
∋:=-weaken= (S, inΓ) (▶Z cloA) upA = S= (S, inΓ) upA
∋:=-weaken= (S, inΓ) (▶S, newΓ x) upA = S, (∋:=-weaken= inΓ newΓ upA)
∋:=-weaken= (S∙ inΓ up) (▶Z cloA) upA = S= (S∙ inΓ up) upA
∋:=-weaken= (S∙ {A = A} inΓ up) (▶S∙ {k = k} newΓ x) upA with ↑ty-total A k
... |  A' , upA'  = S∙ (∋:=-weaken= inΓ newΓ upA') (↑ty-comm0 up upA upA')
∋:=-weaken= (S^ inΓ up) (▶Z cloA) upA = S= (S^ inΓ up) upA
∋:=-weaken= (S^ {A = A} inΓ up) (▶S^ {k = k} newΓ x) upA with ↑ty-total A k
... |  A' , upA'  = S^ (∋:=-weaken= inΓ newΓ upA') (↑ty-comm0 up upA upA')
∋:=-weaken= (S= inΓ up) (▶Z cloA) upA = S= (S= inΓ up) upA
∋:=-weaken= (S= {A = A} inΓ up) (▶S= {k = k} newΓ x x₁) upA with ↑ty-total A k
... |  A' , upA'  = S= (∋:=-weaken= inΓ newΓ upA') (↑ty-comm0 up upA upA')

∋∙-weaken= : Γ ∋∙ X
       Γ  k ,= T  Γ'
       Γ' ∋∙ punchIn k X
∋∙-weaken= Z (▶Z cloA) = S= Z
∋∙-weaken= Z (▶S∙ newΓ x) = Z
∋∙-weaken= (S, inΓ) (▶Z cloA) = S= (S, inΓ)
∋∙-weaken= (S, inΓ) (▶S, newΓ x) = S, (∋∙-weaken= inΓ newΓ)
∋∙-weaken= (S∙ inΓ) (▶Z cloA) = S= (S∙ inΓ)
∋∙-weaken= (S∙ inΓ) (▶S∙ newΓ x) = S∙ (∋∙-weaken= inΓ newΓ)
∋∙-weaken= (S= inΓ) (▶Z cloA) = S= (S= inΓ)
∋∙-weaken= (S= inΓ) (▶S= newΓ x x₁) = S= (∋∙-weaken= inΓ newΓ)
∋∙-weaken= (S^ inΓ) (▶Z cloA) = S= (S^ inΓ)
∋∙-weaken= (S^ inΓ) (▶S^ newΓ x) = S^ (∋∙-weaken= inΓ newΓ)
∋∙-weaken= (S⋈ inΓ) (▶Z regA) = S= (S⋈ inΓ)
∋∙-weaken= (S⋈ inΓ) (▶S⋈ newΓ) = S⋈ (∋∙-weaken= inΓ newΓ)


∋=-weaken= : Γ ∋= X
       Γ  k ,= T  Γ'
       Γ' ∋= punchIn k X
∋=-weaken= Z (▶Z cloA) = S= Z
∋=-weaken= Z (▶S= newΓ x x₁) = Z
∋=-weaken= (S, inΓ) (▶Z cloA) = S= (S, inΓ)
∋=-weaken= (S, inΓ) (▶S, newΓ x) = S, (∋=-weaken= inΓ newΓ)
∋=-weaken= (S∙ inΓ) (▶Z cloA) = S= (S∙ inΓ)
∋=-weaken= (S∙ inΓ) (▶S∙ newΓ x) = S∙ (∋=-weaken= inΓ newΓ)
∋=-weaken= (S= inΓ) (▶Z cloA) = S= (S= inΓ)
∋=-weaken= (S= inΓ) (▶S= newΓ x x₁) = S= (∋=-weaken= inΓ newΓ)
∋=-weaken= (S^ inΓ) (▶Z cloA) = S= (S^ inΓ)
∋=-weaken= (S^ inΓ) (▶S^ newΓ x) = S^ (∋=-weaken= inΓ newΓ)

∋^-weaken= : Γ ∋^ X
       Γ  k ,= T  Γ'
       Γ' ∋^ punchIn k X
∋^-weaken= Z (▶Z cloA) = S= Z
∋^-weaken= Z (▶S^ newΓ _) = Z
∋^-weaken= (S, inΓ) (▶Z cloA) = S= (S, inΓ)
∋^-weaken= (S, inΓ) (▶S, newΓ x) = S, (∋^-weaken= inΓ newΓ)
∋^-weaken= (S∙ inΓ) (▶Z cloA) = S= (S∙ inΓ)
∋^-weaken= (S∙ inΓ) (▶S∙ newΓ x) = S∙ (∋^-weaken= inΓ newΓ)
∋^-weaken= (S= inΓ) (▶Z cloA) = S= (S= inΓ)
∋^-weaken= (S= inΓ) (▶S= newΓ x x₁) = S= (∋^-weaken= inΓ newΓ)
∋^-weaken= (S^ inΓ) (▶Z cloA) = S= (S^ inΓ)
∋^-weaken= (S^ inΓ) (▶S^ newΓ x) = S^ (∋^-weaken= inΓ newΓ)

⊢r-weaken= : Γ ⊢r A
            Γ  k ,= T  Γ'
            A ↑ty k  A'
            Γ' ⊢r A'
⊢r-weaken= ⊢r-int new ↑ty-int = ⊢r-int
⊢r-weaken= (⊢r-var-∙ inΓ) new ↑ty-var = ⊢r-var-∙ (∋∙-weaken= inΓ new)
⊢r-weaken= (⊢r-arr regA regA₁) new (↑ty-arr upA upA₁) = ⊢r-arr (⊢r-weaken= regA new upA) (⊢r-weaken= regA₁ new upA₁)
⊢r-weaken= {T = T} (⊢r-∀ regA) new (↑ty-∀ upA)
  with  T' , upT ↑ty0-total T = ⊢r-∀ (⊢r-weaken= regA (▶S∙ new upT) upA)


▶=-𝕣 : Γ  k ,= T  Γ'
      𝕣 Γ  k ,= T  𝕣 Γ'
▶=-𝕣 (▶Z regA) = ▶Z (⊢r-𝕣' regA)
▶=-𝕣 (▶S, new up) = ▶S, (▶=-𝕣 new) up
▶=-𝕣 (▶S^ new x) = ▶S^ (▶=-𝕣 new) x
▶=-𝕣 (▶S∙ new x) = ▶S∙ (▶=-𝕣 new) x
▶=-𝕣 (▶S= new x x₁) = ▶S= (▶=-𝕣 new) x x₁
▶=-𝕣 (▶S⋈ new) = new

▶⨟=-unique : Γ  Γ  k ,= T  Γ'  Δ'
            Γ'  Δ'
▶⨟=-unique (▶Z regA) = refl
▶⨟=-unique (▶S, new up) with refl▶⨟=-unique new = refl
▶⨟=-unique (▶S^ new x) with refl▶⨟=-unique new = refl
▶⨟=-unique (▶S∙ new x) with refl▶⨟=-unique new = refl
▶⨟=-unique (▶S= new x x₁) with refl▶⨟=-unique new = refl
▶⨟=-unique (▶S⋈ new) with refl▶⨟=-unique new = refl

▶⨟=-▶=-l : Γ  Δ  k ,= T  Γ'  Δ'
          Γ  k ,= T  Γ'
▶⨟=-▶=-l (▶Z regA) = ▶Z regA
▶⨟=-▶=-l (▶S, new up) = ▶S, (▶⨟=-▶=-l new) up
▶⨟=-▶=-l (▶S^ new x) = ▶S^ (▶⨟=-▶=-l new) x
▶⨟=-▶=-l (▶S^= new x x₁) = ▶S^ (▶⨟=-▶=-l new) x
▶⨟=-▶=-l (▶S∙ new x) = ▶S∙ (▶⨟=-▶=-l new) x
▶⨟=-▶=-l (▶S= new x x₁) = ▶S= (▶⨟=-▶=-l new) x x₁
▶⨟=-▶=-l (▶S⋈ new) = ▶S⋈ (▶⨟=-▶=-l new)

▶=-▶⨟= : Γ  k ,= T  Γ'
        Γ  Γ  k ,= T  Γ'  Γ'
▶=-▶⨟= (▶Z regA) = ▶Z regA
▶=-▶⨟= (▶S, new up) = ▶S, (▶=-▶⨟= new) up
▶=-▶⨟= (▶S^ new x) = ▶S^ (▶=-▶⨟= new) x
▶=-▶⨟= (▶S∙ new x) = ▶S∙ (▶=-▶⨟= new) x
▶=-▶⨟= (▶S= new x x₁) = ▶S= (▶=-▶⨟= new) x x₁
▶=-▶⨟= (▶S⋈ new) = ▶S⋈ (▶=-▶⨟= new)



tregular-weaken= : TRegular Γ
                  Γ  k ,= T  Γ'
                  TRegular Γ'
tregular-weaken= reg-Z (▶Z regA) = reg-S= reg-Z regA
tregular-weaken= (reg-S, regΓ regA) (▶Z regA₁) = reg-S= (reg-S, regΓ regA) regA₁
tregular-weaken= (reg-S, regΓ regA) (▶S, new up) = reg-S, (tregular-weaken= regΓ new) (⊢r-weaken= regA new up)
tregular-weaken= (reg-S∙ regΓ) (▶Z regA) = reg-S= (reg-S∙ regΓ) regA
tregular-weaken= (reg-S∙ regΓ) (▶S∙ new x) = reg-S∙ (tregular-weaken= regΓ new)
tregular-weaken= (reg-S^ regΓ) (▶Z regA) = reg-S= (reg-S^ regΓ) regA
tregular-weaken= (reg-S^ regΓ) (▶S^ new x) = reg-S^ (tregular-weaken= regΓ new)
tregular-weaken= (reg-S= regΓ regA) (▶Z regA₁) = reg-S= (reg-S= regΓ regA) regA₁
tregular-weaken= (reg-S= regΓ regA) (▶S= new x x₁) = reg-S= (tregular-weaken= regΓ new) (⊢r-weaken= regA new x₁)

sregular-weaken= : SRegular Γ
                  Γ  k ,= T  Γ'
                  SRegular Γ'
sregular-weaken= (reg-Z regΓ) (▶Z regA) = reg-S= (reg-Z regΓ) regA
sregular-weaken= (reg-Z regΓ) (▶S⋈ new) = reg-Z (tregular-weaken= regΓ new)
sregular-weaken= (reg-S∙ regΓ) (▶Z regA) = reg-S= (reg-S∙ regΓ) regA
sregular-weaken= (reg-S∙ regΓ) (▶S∙ new x) = reg-S∙ (sregular-weaken= regΓ new)
sregular-weaken= (reg-S^ regΓ) (▶Z regA) = reg-S= (reg-S^ regΓ) regA
sregular-weaken= (reg-S^ regΓ) (▶S^ new x) = reg-S^ (sregular-weaken= regΓ new)
sregular-weaken= (reg-S= regΓ regA) (▶Z regA₁) = reg-S= (reg-S= regΓ regA) regA₁
sregular-weaken= (reg-S= regΓ regA) (▶S= new x x₁) = reg-S= (sregular-weaken= regΓ new) (⊢r-weaken= regA new x₁)

∋⦂-weaken= : Γ  x  A
            Γ  k ,= T  Γ'
            A ↑ty k  A'
            Γ'  x  A'
∋⦂-weaken= Z (▶Z regA) upA = S= Z upA
∋⦂-weaken= Z (▶S, new up) upA
  with refl↑ty-unique up upA = Z
∋⦂-weaken= (S, inΓ) (▶Z regA) upA = S= (S, inΓ) upA
∋⦂-weaken= (S, inΓ) (▶S, new up) upA = S, (∋⦂-weaken= inΓ new upA)
∋⦂-weaken= (S∙ inΓ up) (▶Z regA) upA = S= (S∙ inΓ up) upA
∋⦂-weaken= {k = #S k} (S∙ {A = A} inΓ up) (▶S∙ new x) upA
  with  A' , upA' ↑ty-total A k = S∙ (∋⦂-weaken= inΓ new upA') (↑ty-comm0 up upA upA')
∋⦂-weaken= (S^ inΓ up) (▶Z regA) upA = S= (S^ inΓ up) upA
∋⦂-weaken= {k = #S k} (S^ {A = A} inΓ up) (▶S^ new x) upA
  with  A' , upA' ↑ty-total A k = S^ (∋⦂-weaken= inΓ new upA') (↑ty-comm0 up upA upA')
∋⦂-weaken= (S= inΓ up) (▶Z regA) upA = S= (S= inΓ up) upA
∋⦂-weaken= {k = #S k} (S= {A = A} inΓ up) (▶S= new x x₁) upA
  with  A' , upA' ↑ty-total A k = S= (∋⦂-weaken= inΓ new upA') (↑ty-comm0 up upA upA')

⊢c-weaken= : Γ ⊢c A
            Γ  k ,= T  Γ'
            A ↑ty k  A'
            Γ' ⊢c A'
⊢c-weaken= ⊢c-int new ↑ty-int = ⊢c-int
⊢c-weaken= (⊢c-var-∙ inΔ) new ↑ty-var = ⊢c-var-∙ (∋∙-weaken= inΔ new)
⊢c-weaken= (⊢c-var-= inΔ) new ↑ty-var = ⊢c-var-= (∋=-weaken= inΔ new)
⊢c-weaken= (⊢c-arr cloA cloA₁) new (↑ty-arr upA upA₁) = ⊢c-arr (⊢c-weaken= cloA new upA) (⊢c-weaken= cloA₁ new upA₁)
⊢c-weaken= {T = T} (⊢c-∀ cloA) new (↑ty-∀ upA)
  with  T' , upT ↑ty0-total T = ⊢c-∀ (⊢c-weaken= cloA (▶S∙ new upT) upA)

⊢o-weaken= : Γ ⊢o A
            Γ  k ,= T  Γ'
            A ↑ty k  A'
            Γ' ⊢o A'
⊢o-weaken= (⊢o-var-^ x) new ↑ty-var = ⊢o-var-^ (∋^-weaken= x new)
⊢o-weaken= (⊢o-arr-l opnA) new (↑ty-arr upA upA₁) = ⊢o-arr-l (⊢o-weaken= opnA new upA)
⊢o-weaken= (⊢o-arr-r opnA) new (↑ty-arr upA upA₁) = ⊢o-arr-r (⊢o-weaken= opnA new upA₁)
⊢o-weaken= {T = T} (⊢o-∀ opnA) new (↑ty-∀ upA)
  with  T' , upT ↑ty0-total T = ⊢o-∀ (⊢o-weaken= opnA (▶S∙ new upT) upA)

≫-weaken= : Γ  A  B
           Γ  k ,= T  Γ'
           A ↑ty k  A'
           B ↑ty k  B'
           Γ'  A'  B'
≫-weaken= grd-int new ↑ty-int ↑ty-int = grd-int
≫-weaken= (grd-var= x) new ↑ty-var upB = grd-var= (∋:=-weaken= x new upB)
≫-weaken= (grd-var∙ x) new ↑ty-var ↑ty-var = grd-var∙ (∋∙-weaken= x new)
≫-weaken= (grd-arr grd grd₁) new (↑ty-arr upA upA₁) (↑ty-arr upB upB₁) = grd-arr (≫-weaken= grd new upA upB) (≫-weaken= grd₁ new upA₁ upB₁)
≫-weaken= {T = T} (grd-∀ grd) new (↑ty-∀ upA) (↑ty-∀ upB)
  with  T' , upT ↑ty0-total T = grd-∀ (≫-weaken= grd (▶S∙ new upT) upA upB)


inst-weaken= : [ A / X ] Γ  Δ
              Γ  Δ  k ,= T  Γ'  Δ'
              A ↑ty k  A'
              [ A' / punchIn k X ] Γ'  Δ'
inst-weaken= (⟹^0 up regA env) (▶Z regA₁) upA = ⟹=S (⟹^0 up regA env) upA regA₁
inst-weaken= (⟹^0 up regA env) (▶S^= new x x₁) upA with refl▶⨟=-unique new = ⟹^0 (↑ty-comm0 up upA x₁)
                                                                                      (⊢r-weaken= regA (▶⨟=-▶=-l new) x₁)
                                                                                      (sregular-weaken= env (▶⨟=-▶=-l new))
inst-weaken= (⟹^S inst up1) (▶Z regA) upA = ⟹=S (⟹^S inst up1) upA regA
inst-weaken= {k = #S k} (⟹^S {A = A} inst up1) (▶S^ new x) upA
  with  A' , upA' ↑ty-total A k = ⟹^S (inst-weaken= inst new upA') (↑ty-comm0 up1 upA upA')
inst-weaken= (⟹∙S inst up1) (▶Z regA) upA = ⟹=S (⟹∙S inst up1) upA regA
inst-weaken= {k = #S k} (⟹∙S {A = A} inst up1) (▶S∙ new x) upA
  with  A' , upA' ↑ty-total A k  = ⟹∙S (inst-weaken= inst new upA') (↑ty-comm0 up1 upA upA')
inst-weaken= (⟹=S inst up1 regB) (▶Z regA) upA = ⟹=S (⟹=S inst up1 regB) upA regA
inst-weaken= {k = #S k} (⟹=S {A = A} inst up1 regB) (▶S= new x x₁) upA
  with  A' , upA' ↑ty-total A k = ⟹=S (inst-weaken= inst new upA') (↑ty-comm0 up1 upA upA') (⊢r-weaken= regB (▶⨟=-▶=-l new) x₁)