module Implicit.Decl.AuxLemmas where

open import Implicit.Language.All

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'

▶'=-∋:= : Γ ▶' k ,= T  Γ'
        T ↑ty k  T'
        Γ'  k := T'
▶'=-∋:= (▶'Z regA) upT = Z upT
▶'=-∋:= (▶'S, new up) upT = S, (▶'=-∋:= new upT)
▶'=-∋:= {k = #S k} (▶'S^ {A = A} new x) upT
  with  A' , upA ↑ty-total A k
  = S^ (▶'=-∋:= new upA) (↑ty-comm0 x upT upA)
▶'=-∋:= {k = #S k} (▶'S∙ {A = A} new x) upT
  with  A' , upA ↑ty-total A k
  = S∙ (▶'=-∋:= new upA) (↑ty-comm0 x upT upA)
▶'=-∋:= {k = #S k} (▶'S= {A = A} new up1 up2) upT
  with  A' , upA ↑ty-total A k
  = S= (▶'=-∋:= new upA) (↑ty-comm0 up1 upT upA)

▶'-∋∙-helper : Γ ∋∙ X
              Γ ▶' #0 ,= B  Γ'
              Γ' ∋∙ #S X
▶'-∋∙-helper inΓ (▶'Z regA) = S= inΓ
▶'-∋∙-helper (S, inΓ) (▶'S, new up) = S, (▶'-∋∙-helper inΓ new)


▶'-∋∙ : Γ ▶' k ,= B  Γ'
       (¬p : k  X)
       Γ ∋∙ punchOut ¬p
       Γ' ∋∙ X
▶'-∋∙ {k = #0} {X = #0} new ¬p inΓ = ⊥-elim (¬p refl)
▶'-∋∙ {k = #0} {X = #S X} new ¬p inΓ = ▶'-∋∙-helper inΓ new
▶'-∋∙ {k = #S k} {X = #0} (▶'S∙ new x) ¬p Z = Z
▶'-∋∙ {k = #S k} {X = #0} (▶'S, new up) ¬p (S, inΓ) = S, (▶'-∋∙ new ¬p inΓ)
▶'-∋∙ {k = #S k} {X = #S X} (▶'S, new up) ¬p (S, inΓ) = S, (▶'-∋∙ new ¬p inΓ)
▶'-∋∙ {k = #S k} {X = #S X} (▶'S^ new x) ¬p (S^ inΓ) = S^ (▶'-∋∙ new  x₁  ¬p (cong #S x₁)) inΓ)
▶'-∋∙ {k = #S k} {X = #S X} (▶'S∙ new x) ¬p (S∙ inΓ) = S∙ (▶'-∋∙ new  x₁  ¬p (cong #S x₁)) inΓ)
▶'-∋∙ {k = #S k} {X = #S X} (▶'S= new x x₁) ¬p (S= inΓ) = S= (▶'-∋∙ new  x₂  ¬p (cong #S x₂)) inΓ)

∋∙-∙⟹-∋:=-prv : Γ ∋∙ X
             [ T' / k ] Γ ∙⟹ Γ'
             Γ' ∋= X
             X  k
∋∙-∙⟹-∋:=-prv Z (∙⟹^0 up regA) Z = refl
∋∙-∙⟹-∋:=-prv (S, inΓ) (∙⟹,S new) (S, inΓ') = ∋∙-∙⟹-∋:=-prv inΓ new inΓ'
∋∙-∙⟹-∋:=-prv (S∙ inΓ) (∙⟹^0 up regA) (S= inΓ') = ⊥-elim (∋∙-∋=-false inΓ inΓ')
∋∙-∙⟹-∋:=-prv (S∙ inΓ) (∙⟹∙S new up1) (S∙ inΓ') = cong #S (∋∙-∙⟹-∋:=-prv inΓ new inΓ')
∋∙-∙⟹-∋:=-prv (S= inΓ) (∙⟹=S new up1) (S= inΓ') = cong #S (∋∙-∙⟹-∋:=-prv inΓ new inΓ')
∋∙-∙⟹-∋:=-prv (S^ inΓ) (∙⟹^S new up1) (S^ inΓ') = cong #S (∋∙-∙⟹-∋:=-prv inΓ new inΓ')


≫-↑ty-st' : Γ ⊢r A
           T ↑ty k  T'
           [ T' / k ] Γ ∙⟹ Γ'
           Γ'  A  A%
           A* ↑ty k  A%
            k / T  A  A*
≫-↑ty-st' ⊢r-int upT new grd-int ↑ty-int = st-int
≫-↑ty-st' (⊢r-var-∙ inΓ) upT new (grd-var= x) upA*
  with refl∋∙-∙⟹-∋:=-prv inΓ new (∋:=to∋= x)
  with refl∋:=-unique (∙⟹-∋:= new) x
  with refl↑ty-unique-inver upT upA* = st-var stx-eq
≫-↑ty-st' {k = k}(⊢r-var-∙ inΓ) upT new (grd-var∙ x) (↑ty-var {X = X})
  = st-var (stx-neq-helper helper (punchIn-injective k X (punchOut helper) (sym (punchIn-punchOut {i = k} {j = punchIn k X} helper))))
  where helper : k  punchIn k X
        helper = ∙⟹-∋∙-neq inΓ new x
≫-↑ty-st' (⊢r-arr regA regA₁) upT new (grd-arr grd grd₁) (↑ty-arr upA* upA*₁) = st-arr (≫-↑ty-st' regA upT new grd upA*)
                                                                                       (≫-↑ty-st' regA₁ upT new grd₁ upA*₁)
≫-↑ty-st' {T = T} {k = k} (⊢r-∀ regA) upT new (grd-∀ grd) (↑ty-∀ upA*)
  with  T' , upT' ↑ty0-total T
  with  T1 , upT1 ↑ty-total T' (#S k) = st-∀ upT' (≫-↑ty-st' regA upT1 (∙⟹∙S new (↑ty-comm0 upT' upT1 upT)) grd upA*)

≫-↑ty-st'0 : Γ ,∙ ⊢r A
            Γ ⊢r B
            Γ ,= B  A  A%
            ↑ty0 A*  A%
             B  A  A*
≫-↑ty-st'0 {B = B} regA regB grd upA*
  with  B' , upB ↑ty0-total B = ≫-↑ty-st' regA upB (∙⟹^0 upB regB) grd upA*


st-↑ty-≫ :  k / B  A  A*
          A* ↑ty k  A*'
          Γ ⊢r A*
          Γ ▶' k ,= B  Γ'
          Γ'  A  A*'
st-↑ty-≫ st-int ↑ty-int regA* new = grd-int
st-↑ty-≫ (st-var stx-eq) upA* regA* new = grd-var= (▶'=-∋:= new upA*)
st-↑ty-≫ {k = k} (st-var (stx-neq ¬p)) ↑ty-var (⊢r-var-∙ inΓ) new rewrite punchIn-punchOut {i = k} ¬p
  = grd-var∙ (▶'-∋∙ new ¬p inΓ)
st-↑ty-≫ (st-arr stA stA₁) (↑ty-arr upA* upA*₁) (⊢r-arr regA* regA*₁) new = grd-arr (st-↑ty-≫ stA upA* regA* new)
                                                                                    (st-↑ty-≫ stA₁ upA*₁ regA*₁ new)
st-↑ty-≫ (st-∀ up stA) (↑ty-∀ upA*) (⊢r-∀ regA*) new = grd-∀ (st-↑ty-≫ stA upA* regA* (▶'S∙ new up))

st-↑ty-≫0 :  B  A  A*
           Γ ⊢r A*
           ↑ty0 A*  A*'
           Γ ⊢r B
           Γ ,= B  A  A*'
st-↑ty-≫0 st regA upA* regB = st-↑ty-≫ st upA* regA (▶'Z regB)