module A201801.LPTTDerivations where

open import A201801.Prelude
open import A201801.Category
open import A201801.Fin
open import A201801.Vec
open import A201801.VecLemmas
open import A201801.AllVec
open import A201801.S4TTTerms
open import A201801.S4TTTermsLemmas
open import A201801.LPTTTypes
open import A201801.LPTTTypesLemmas
open import A201801.LPTTAsserts


--------------------------------------------------------------------------------


infix 3 _⊢_⦂_valid[_]
data _⊢_⦂_valid[_] :  {d g}  Asserts d  Term d g  Type d  Types d g  Set
  where
    var :  {d g I A}  {Δ : Asserts d} {Γ : Types d g}
                       Γ ∋⟨ I  A
                       Δ  VAR I  A valid[ Γ ]

    lam :  {d g M A B}  {Δ : Asserts d} {Γ : Types d g}
                         Δ  M  B valid[ Γ , A ]
                         Δ  LAM M  A  B valid[ Γ ]

    app :  {d g M N A B}  {Δ : Asserts d} {Γ : Types d g}
                           Δ  M  A  B valid[ Γ ]  Δ  N  A valid[ Γ ]
                           Δ  APP M N  B valid[ Γ ]

    mvar :  {d g I M A}  {Δ : Asserts d} {Γ : Types d g}
                          Δ ∋◆⟨ I  ⟪⊫ M  A   -- NOTE: This is more than Artemov-Bonelli
                          Δ  MVAR I  A valid[ Γ ]

    box :  {d g M A}  {Δ : Asserts d} {Γ : Types d g}
                       Δ  M  A valid[  ]
                       Δ  BOX M  [ M ] A valid[ Γ ]

    letbox :  {d g M N Q A B}  {Δ : Asserts d} {Γ : Types d g}
                                  {B′ : Type d} {{p : TMCUT Q B  B′}}
                                Δ  M  [ Q ] A valid[ Γ ]  Δ , ⟪⊫ Q  A   N  B valid[ TMWKS Γ ]  -- NOTE
                                Δ  LETBOX M N  B′ valid[ Γ ]


infix 3 _⊢_⦂_allvalid[_]
_⊢_⦂_allvalid[_] :  {d g n}  Asserts d  Terms d g n  Types d n  Types d g  Set
Δ  τ  Ξ allvalid[ Γ ] = All (\ { (M , A)  Δ  M  A valid[ Γ ] }) (zip τ Ξ)


--------------------------------------------------------------------------------


-- ren : ∀ {d g g′ e M A} → {Δ : Asserts d} {Γ : Types g} {Γ′ : Types g′}
--                        → Γ′ ⊇⟨ e ⟩ Γ → Δ ⊢ M ⦂ A valid[ Γ ]
--                        → Δ ⊢ REN e M ⦂ A valid[ Γ′ ]
-- ren η (var i)      = var (ren∋ η i)
-- ren η (lam 𝒟)      = lam (ren (keep η) 𝒟)
-- ren η (app 𝒟 ℰ)    = app (ren η 𝒟) (ren η ℰ)
-- ren η (mvar i)     = mvar i
-- ren η (box 𝒟)      = box 𝒟
-- ren η (letbox 𝒟 ℰ) = letbox (ren η 𝒟) (ren η ℰ)


-- rens : ∀ {d g g′ e n} → {Δ : Asserts d} {Γ : Types g} {Γ′ : Types g′}
--                          {τ : Terms d g n} {Ξ : Types n}
--                       → Γ′ ⊇⟨ e ⟩ Γ → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ]
--                       → Δ ⊢ RENS e τ ⦂ Ξ allvalid[ Γ′ ]
-- rens {τ = ∙}     {∙}     η ∙       = ∙
-- rens {τ = τ , M} {Ξ , A} η (ξ , 𝒟) = rens η ξ , ren η 𝒟


-- --------------------------------------------------------------------------------


-- mren : ∀ {d d′ g e M A} → {Δ : Asserts d} {Δ′ : Asserts d′} {Γ : Types g}
--                         → Δ′ ⊇⟨ e ⟩ Δ → Δ ⊢ M ⦂ A valid[ Γ ]
--                         → Δ′ ⊢ MREN e M ⦂ A valid[ Γ ]
-- mren η (var i)      = var i
-- mren η (lam 𝒟)      = lam (mren η 𝒟)
-- mren η (app 𝒟 ℰ)    = app (mren η 𝒟) (mren η ℰ)
-- mren η (mvar i)     = mvar (ren∋ η i)
-- mren η (box 𝒟)      = box (mren η 𝒟)
-- mren η (letbox 𝒟 ℰ) = letbox (mren η 𝒟) (mren (keep η) ℰ)


-- mrens : ∀ {d d′ g e n} → {Δ : Asserts d} {Δ′ : Asserts d′} {Γ : Types g}
--                           {τ : Terms d g n} {Ξ : Types n}
--                        → Δ′ ⊇⟨ e ⟩ Δ → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ]
--                        → Δ′ ⊢ MRENS e τ ⦂ Ξ allvalid[ Γ ]
-- mrens {τ = ∙}     {∙}     η ∙       = ∙
-- mrens {τ = τ , M} {Ξ , A} η (ξ , 𝒟) = mrens η ξ , mren η 𝒟


-- mrens* : ∀ {d d′ e n} → {Δ : Asserts d} {Δ′ : Asserts d′}
--                          {τ : Terms* d n} {Ξ : Asserts n}
--                       → Δ′ ⊇⟨ e ⟩ Δ → Δ ⊢ τ ⦂ Ξ allvalid*
--                       → Δ′ ⊢ MRENS* e τ ⦂ Ξ allvalid*
-- mrens* {τ = ∙}     {∙}     η ∙       = ∙
-- mrens* {τ = τ , M} {Ξ , A} η (ξ , 𝒟) = mrens* η ξ , mren η 𝒟


-- --------------------------------------------------------------------------------


-- wk : ∀ {B d g M A} → {Δ : Asserts d} {Γ : Types g}
--                    → Δ ⊢ M ⦂ A valid[ Γ ]
--                    → Δ ⊢ WK M ⦂ A valid[ Γ , B ]
-- wk 𝒟 = ren (drop id⊇) 𝒟


-- wks : ∀ {A d g n} → {Δ : Asserts d} {Γ : Types g}
--                      {τ : Terms d g n} {Ξ : Types n}
--                   → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ]
--                   → Δ ⊢ WKS τ ⦂ Ξ allvalid[ Γ , A ]
-- wks ξ = rens (drop id⊇) ξ


-- vz : ∀ {d g A} → {Δ : Asserts d} {Γ : Types g}
--                → Δ ⊢ VZ ⦂ A valid[ Γ , A ]
-- vz = var zero


-- lifts : ∀ {A d g n} → {Δ : Asserts d} {Γ : Types g}
--                        {τ : Terms d g n} {Ξ : Types n}
--                     → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ]
--                     → Δ ⊢ LIFTS τ ⦂ Ξ , A allvalid[ Γ , A ]
-- lifts ξ = wks ξ , vz


-- vars : ∀ {d g g′ e} → {Δ : Asserts d} {Γ : Types g} {Γ′ : Types g′}
--                     → Γ′ ⊇⟨ e ⟩ Γ
--                     → Δ ⊢ VARS e ⦂ Γ allvalid[ Γ′ ]
-- vars done     = ∙
-- vars (drop η) = wks (vars η)
-- vars (keep η) = lifts (vars η)


-- ids : ∀ {d g} → {Δ : Asserts d} {Γ : Types g}
--               → Δ ⊢ IDS ⦂ Γ allvalid[ Γ ]
-- ids = vars id⊇


-- --------------------------------------------------------------------------------


-- mwk : ∀ {B d g M A} → {Δ : Asserts d} {Γ : Types g}
--                     → Δ ⊢ M ⦂ A valid[ Γ ]
--                     → Δ , ⟪⊫ B ⟫ ⊢ MWK M ⦂ A valid[ Γ ]
-- mwk 𝒟 = mren (drop id⊇) 𝒟


-- mwks : ∀ {A d g n} → {Δ : Asserts d} {Γ : Types g}
--                       {τ : Terms d g n} {Ξ : Types n}
--                    → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ]
--                    → Δ , ⟪⊫ A ⟫ ⊢ MWKS τ ⦂ Ξ allvalid[ Γ ]
-- mwks ξ = mrens (drop id⊇) ξ


-- mwks* : ∀ {A d n} → {Δ : Asserts d}
--                      {τ : Terms* d n} {Ξ : Asserts n}
--                   → Δ ⊢ τ ⦂ Ξ allvalid*
--                   → Δ , ⟪⊫ A ⟫ ⊢ MWKS* τ ⦂ Ξ allvalid*
-- mwks* ξ = mrens* (drop id⊇) ξ


-- mvz : ∀ {d g A} → {Δ : Asserts d} {Γ : Types g}
--                 → Δ , ⟪⊫ A ⟫ ⊢ MVZ ⦂ A valid[ Γ ]
-- mvz = mvar zero


-- mlifts* : ∀ {A d n} → {Δ : Asserts d}
--                        {τ : Terms* d n} {Ξ : Asserts n}
--                     → Δ ⊢ τ ⦂ Ξ allvalid*
--                     → Δ , ⟪⊫ A ⟫ ⊢ MLIFTS* τ ⦂ Ξ , ⟪⊫ A ⟫ allvalid*
-- mlifts* ξ = mwks* ξ , mvz


-- mvars* : ∀ {d d′ e} → {Δ : Asserts d} {Δ′ : Asserts d′}
--                     → Δ′ ⊇⟨ e ⟩ Δ
--                     → Δ′ ⊢ MVARS* e ⦂ Δ allvalid*
-- mvars* done     = ∙
-- mvars* (drop η) = mwks* (mvars* η)
-- mvars* (keep η) = mlifts* (mvars* η)


-- mids* : ∀ {d} → {Δ : Asserts d}
--               → Δ ⊢ MIDS* ⦂ Δ allvalid*
-- mids* = mvars* id⊇


-- --------------------------------------------------------------------------------


-- sub : ∀ {d g n M A} → {Δ : Asserts d} {Γ : Types g}
--                        {τ : Terms d g n} {Ξ : Types n}
--                     → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ] → Δ ⊢ M ⦂ A valid[ Ξ ]
--                     → Δ ⊢ SUB τ M ⦂ A valid[ Γ ]
-- sub ξ (var i)      = get ξ (zip∋₂ i)
-- sub ξ (lam 𝒟)      = lam (sub (lifts ξ) 𝒟)
-- sub ξ (app 𝒟 ℰ)    = app (sub ξ 𝒟) (sub ξ ℰ)
-- sub ξ (mvar i)     = mvar i
-- sub ξ (box 𝒟)      = box 𝒟
-- sub ξ (letbox 𝒟 ℰ) = letbox (sub ξ 𝒟) (sub (mwks ξ) ℰ)


-- subs : ∀ {d g n m} → {Δ : Asserts d} {Γ : Types g}
--                       {τ : Terms d g n} {Ξ : Types n}
--                       {υ : Terms d n m} {Ψ : Types m}
--                    → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ] → Δ ⊢ υ ⦂ Ψ allvalid[ Ξ ]
--                    → Δ ⊢ SUBS τ υ ⦂ Ψ allvalid[ Γ ]
-- subs {υ = ∙}     {∙}     ξ ∙       = ∙
-- subs {υ = υ , M} {Ψ , A} ξ (ψ , 𝒟) = subs ξ ψ , sub ξ 𝒟


-- --------------------------------------------------------------------------------


-- msub : ∀ {d g n M A} → {Δ : Asserts d} {Γ : Types g}
--                         {τ : Terms* d n} {Ξ : Asserts n}
--                      → Δ ⊢ τ ⦂ Ξ allvalid* → Ξ ⊢ M ⦂ A valid[ Γ ]
--                      → Δ ⊢ MSUB τ M ⦂ A valid[ Γ ]
-- msub ξ (var i)      = var i
-- msub ξ (lam 𝒟)      = lam (msub ξ 𝒟)
-- msub ξ (app 𝒟 ℰ)    = app (msub ξ 𝒟) (msub ξ ℰ)
-- msub ξ (mvar i)     = sub ∙ (get ξ (zip∋₂ i))
-- msub ξ (box 𝒟)      = box (msub ξ 𝒟)
-- msub ξ (letbox 𝒟 ℰ) = letbox (msub ξ 𝒟) (msub (mlifts* ξ) ℰ)


-- msubs : ∀ {d g n m} → {Δ : Asserts d} {Γ : Types g}
--                        {τ : Terms* d n} {Ξ : Asserts n}
--                        {υ : Terms n g m} {Ψ : Types m}
--                     → Δ ⊢ τ ⦂ Ξ allvalid* → Ξ ⊢ υ ⦂ Ψ allvalid[ Γ ]
--                     → Δ ⊢ MSUBS τ υ ⦂ Ψ allvalid[ Γ ]
-- msubs {υ = ∙}     {∙}     ξ ∙       = ∙
-- msubs {υ = υ , M} {Ψ , A} ξ (ψ , 𝒟) = msubs ξ ψ , msub ξ 𝒟


-- msubs* : ∀ {d n m} → {Δ : Asserts d}
--                       {τ : Terms* d n} {Ξ : Asserts n}
--                       {υ : Terms* n m} {Ψ : Asserts m}
--                    → Δ ⊢ τ ⦂ Ξ allvalid* → Ξ ⊢ υ ⦂ Ψ allvalid*
--                    → Δ ⊢ MSUBS* τ υ ⦂ Ψ allvalid*
-- msubs* {υ = ∙}     {∙}           ξ ∙       = ∙
-- msubs* {υ = υ , M} {Ψ , ⟪⊫ A ⟫} ξ (ψ , 𝒟) = msubs* ξ ψ , msub ξ 𝒟


-- --------------------------------------------------------------------------------


-- unlam : ∀ {d g M A B} → {Δ : Asserts d} {Γ : Types g}
--                       → Δ ⊢ M ⦂ A ⊃ B valid[ Γ ]
--                       → Δ ⊢ UNLAM M ⦂ B valid[ Γ , A ]
-- unlam 𝒟 = app (wk 𝒟) vz


-- cut : ∀ {d g M N A B} → {Δ : Asserts d} {Γ : Types g}
--                       → Δ ⊢ M ⦂ A valid[ Γ ] → Δ ⊢ N ⦂ B valid[ Γ , A ]
--                       → Δ ⊢ CUT M N ⦂ B valid[ Γ ]
-- cut 𝒟 ℰ = sub (ids , 𝒟) ℰ


-- pseudocut : ∀ {d g M N A B} → {Δ : Asserts d} {Γ : Types g}
--                             → Δ ⊢ M ⦂ A valid[ Γ ] → Δ ⊢ N ⦂ B valid[ Γ , A ]
--                             → Δ ⊢ PSEUDOCUT M N ⦂ B valid[ Γ ]
-- pseudocut 𝒟 ℰ = app (lam ℰ) 𝒟


-- pseudosub : ∀ {d g n M A} → {Δ : Asserts d} {Γ : Types g}
--                              {τ : Terms d g n} {Ξ : Types n}
--                           → Δ ⊢ τ ⦂ Ξ allvalid[ Γ ] → Δ ⊢ M ⦂ A valid[ Ξ ]
--                           → Δ ⊢ PSEUDOSUB τ M ⦂ A valid[ Γ ]
-- pseudosub {τ = ∙}     {∙}     ∙       𝒟 = ren bot⊇ 𝒟
-- pseudosub {τ = τ , M} {Ξ , B} (ξ , 𝒞) 𝒟 = app (pseudosub ξ (lam 𝒟)) 𝒞


-- exch : ∀ {d g M A B C} → {Δ : Asserts d} {Γ : Types g}
--                        → Δ ⊢ M ⦂ C valid[ Γ , A , B ]
--                        → Δ ⊢ EXCH M ⦂ C valid[ Γ , B , A ]
-- exch 𝒟 = app (app (wk (wk (lam (lam 𝒟)))) vz) (wk vz)


-- --------------------------------------------------------------------------------


-- vau : ∀ {d g M A B} → {Δ : Asserts d} {Γ : Types g}
--                     → Δ , ⟪⊫ A ⟫ ⊢ M ⦂ B valid[ Γ ]
--                     → Δ ⊢ VAU M ⦂ B valid[ Γ , □ A ]
-- vau 𝒟 = letbox vz (wk 𝒟)


-- unvau : ∀ {d g M A B} → {Δ : Asserts d} {Γ : Types g}
--                       → Δ ⊢ M ⦂ B valid[ Γ , □ A ]
--                       → Δ , ⟪⊫ A ⟫ ⊢ UNVAU M ⦂ B valid[ Γ ]
-- unvau 𝒟 = app (lam (mwk 𝒟)) (box mvz)


-- boxapp : ∀ {d g M N A B} → {Δ : Asserts d} {Γ : Types g}
--                          → Δ ⊢ M ⦂ □ (A ⊃ B) valid[ Γ ] → Δ ⊢ N ⦂ □ A valid[ Γ ]
--                          → Δ ⊢ BOXAPP M N ⦂ □ B valid[ Γ ]
-- boxapp 𝒟 ℰ = letbox 𝒟 (letbox (mwk ℰ) (box (app (mwk mvz) mvz)))


-- unbox : ∀ {d g M A} → {Δ : Asserts d} {Γ : Types g}
--                     → Δ ⊢ M ⦂ □ A valid[ Γ ]
--                     → Δ ⊢ UNBOX M ⦂ A valid[ Γ ]
-- unbox 𝒟 = letbox 𝒟 mvz


-- -- NOTE: Local completeness of □

-- rebox : ∀ {d g M A} → {Δ : Asserts d} {Γ : Types g}
--                     → Δ ⊢ M ⦂ □ A valid[ Γ ]
--                     → Δ ⊢ REBOX M ⦂ □ A valid[ Γ ]
-- rebox 𝒟 = letbox 𝒟 (box mvz)


-- dupbox : ∀ {d g M A} → {Δ : Asserts d} {Γ : Types g}
--                      → Δ ⊢ M ⦂ □ A valid[ Γ ]
--                      → Δ ⊢ DUPBOX M ⦂ □ □ A valid[ Γ ]
-- dupbox 𝒟 = letbox 𝒟 (box (box mvz))


-- mcut : ∀ {d g M N A B} → {Δ : Asserts d} {Γ : Types g}
--                        → Δ ⊢ M ⦂ A valid[ ∙ ] → Δ , ⟪⊫ A ⟫ ⊢ N ⦂ B valid[ Γ ]
--                        → Δ ⊢ MCUT M N ⦂ B valid[ Γ ]
-- mcut 𝒟 ℰ = msub (mids* , 𝒟) ℰ


-- -- NOTE: Local soundness of □

-- pseudomcut : ∀ {d g M N A B} → {Δ : Asserts d} {Γ : Types g}
--                              → Δ ⊢ M ⦂ A valid[ ∙ ] → Δ , ⟪⊫ A ⟫ ⊢ N ⦂ B valid[ Γ ]
--                              → Δ ⊢ PSEUDOMCUT M N ⦂ B valid[ Γ ]
-- pseudomcut 𝒟 ℰ = letbox (box 𝒟) ℰ


-- pseudomsub : ∀ {d g n M A} → {Δ : Asserts d} {Γ : Types g}
--                               {τ : Terms* d n} {Ξ : Asserts n}
--                            → Δ ⊢ τ ⦂ Ξ allvalid* → Ξ ⊢ M ⦂ A valid[ Γ ]
--                            → Δ ⊢ PSEUDOMSUB τ M ⦂ A valid[ Γ ]
-- pseudomsub {τ = ∙}     {∙}           ∙       𝒟 = mren bot⊇ 𝒟
-- pseudomsub {τ = τ , M} {Ξ , ⟪⊫ A ⟫} (ξ , 𝒞) 𝒟 = app (pseudomsub ξ (lam (vau 𝒟))) (box 𝒞)


-- mexch : ∀ {d g M A B C} → {Δ : Asserts d} {Γ : Types g}
--                         → Δ , ⟪⊫ A ⟫ , ⟪⊫ B ⟫ ⊢ M ⦂ C valid[ Γ ]
--                         → Δ , ⟪⊫ B ⟫ , ⟪⊫ A ⟫ ⊢ MEXCH M ⦂ C valid[ Γ ]
-- mexch 𝒟 = unvau (unvau (exch (vau (vau 𝒟))))


-- --------------------------------------------------------------------------------