{-# OPTIONS --without-K --safe #-}
open import Level using (0ℓ)
open import Axiom.Extensionality.Propositional
module Mint.Semantics.Properties.Evaluation (fext : Extensionality 0ℓ 0ℓ) where
open import Data.Nat.Properties
open import Data.Product.Relation.Binary.Pointwise.NonDependent using (≡×≡⇒≡)
open import Lib hiding (lookup)
open import Mint.Statics.Syntax
import Mint.Statics.Properties.Ops as Sₚ
open import Mint.Semantics.Domain
open import Mint.Semantics.Properties.Domain fext
open import Mint.Semantics.Evaluation
open import Mint.Semantics.Properties.NoFunExt.Evaluation public
unbox-mon : ∀ {n} (κ : UMoT) → unbox∙ n , a ↘ b → unbox∙ O κ n , a [ κ ∥ n ] ↘ b′ → b [ κ ] ≡ b′
unbox-mon {box a} κ (box↘ n) (box↘ .(O κ n))
  rewrite D-comp a (ins vone n) κ
        | D-comp a (ins (κ ∥ n) 1) (ins vone (O κ n))
        | ins-vone-ø n κ
        | ins-1-ø-ins-vone (κ ∥ n) (O κ n) = refl
unbox-mon κ (unbox∙ {A} n) (unbox∙ .(O κ n))
  rewrite D-comp A (ins vone n) κ
        | D-comp A (ins (κ ∥ n) 1) (ins vone (O κ n))
        | ins-vone-ø n κ
        | ins-1-ø-ins-vone (κ ∥ n) (O κ n) = refl
unbox-mon-⇒ : ∀ {n} (κ : UMoT) → unbox∙ n , a ↘ b → unbox∙ O κ n , a [ κ ∥ n ] ↘ b [ κ ]
unbox-mon-⇒ {_} {_} {n} κ ↘b = let b′ , ↘b′ = helper κ ↘b
                               in subst (unbox∙ O κ n , _ [ κ ∥ _ ] ↘_) (sym (unbox-mon κ ↘b ↘b′)) ↘b′
  where helper : ∀ {n} (κ : UMoT) → unbox∙ n , a ↘ b → ∃ λ b′ → unbox∙ O κ n , a [ κ ∥ n ] ↘ b′
        helper {box a} κ (box↘ n)       = a [ ins (κ ∥ n) 1 ] [ ins vone (O κ n) ]
                                        , box↘ (O κ n)
        helper {↑ (□ A) c} κ (unbox∙ n) = unbox′ (A [ ins (κ ∥ n) 1 ] [ ins vone (O κ n) ]) (O κ n) (c [ κ ∥ n ])
                                        , unbox∙ (O κ n)
unbox-mon-⇐ : ∀ {n} (κ : UMoT) → unbox∙ O κ n , a [ κ ∥ n ] ↘ b′ → ∃ λ b → unbox∙ n , a ↘ b
unbox-mon-⇐ {box a} {_} {n} κ (box↘ .(O κ n))       = a [ ins vone n ] , box↘ n
unbox-mon-⇐ {↑ (□ A) c} {_} {n} κ (unbox∙ .(O κ n)) = unbox′ (A [ ins vone n ]) n c , unbox∙ n
∥-⟦⟧s : ∀ n → ⟦ σ ⟧s ρ ↘ ρ′ → ⟦ σ ∥ n ⟧s ρ ∥ O σ n ↘ ρ′ ∥ n
∥-⟦⟧s 0 ↘ρ′                               = ↘ρ′
∥-⟦⟧s (suc n) ⟦I⟧
  rewrite Sₚ.I-∥ n
        | Sₚ.O-I n                        = ⟦I⟧
∥-⟦⟧s (suc n) ⟦wk⟧                        = ⟦I⟧
∥-⟦⟧s (suc n) (⟦,⟧ ↘ρ′ ↘a)                = ∥-⟦⟧s (suc n) ↘ρ′
∥-⟦⟧s (suc n) (⟦;⟧ {σ} {ρ} {ρ′} {m} ↘ρ′) = subst (⟦ σ ∥ n ⟧s_↘ ρ′ ∥ n) (fext λ l → cong ρ (sym (+-assoc m (O σ n) l))) (∥-⟦⟧s n ↘ρ′)
∥-⟦⟧s (suc n) (⟦∘⟧ {σ = σ} ↘ρ′ ↘ρ″)       = ⟦∘⟧ (∥-⟦⟧s (O σ (suc n)) ↘ρ′) (∥-⟦⟧s (suc n) ↘ρ″)
↦-drop : ∀ ρ → drop ρ ↦ lookup ρ 0 ≡ ρ
↦-drop ρ = fext λ { 0       → ≡×≡⇒≡ (refl , (fext λ { 0       → refl
                                                    ; (suc m) → refl }))
                  ; (suc n) → refl }
mutual
  ⟦⟧-mon : (κ : UMoT) → ⟦ T ⟧ ρ ↘ A → ⟦ T ⟧ ρ [ κ ] ↘ A [ κ ]
  ⟦⟧-mon κ ⟦N⟧                                                    = ⟦N⟧
  ⟦⟧-mon κ (⟦Π⟧ ↘A)                                               = ⟦Π⟧ (⟦⟧-mon κ ↘A)
  ⟦⟧-mon κ (⟦Se⟧ i)                                               = ⟦Se⟧ i
  ⟦⟧-mon {□ T} {ρ} {□ A} κ (⟦□⟧ ↘A)                               = ⟦□⟧ (subst (⟦ T ⟧_↘ A [ ins κ 1 ]) (ext-mon ρ 1 (ins κ 1)) (⟦⟧-mon (ins κ 1) ↘A))
  ⟦⟧-mon κ (⟦v⟧ n)                                                = ⟦v⟧ n
  ⟦⟧-mon κ ⟦ze⟧                                                   = ⟦ze⟧
  ⟦⟧-mon κ (⟦su⟧ ↘A)                                              = ⟦su⟧ (⟦⟧-mon κ ↘A)
  ⟦⟧-mon κ (⟦rec⟧ ↘a ↘b rec↘)                                     = ⟦rec⟧ (⟦⟧-mon κ ↘a) (⟦⟧-mon κ ↘b) (rec-mon κ rec↘)
  ⟦⟧-mon κ (⟦Λ⟧ t)                                                = ⟦Λ⟧ t
  ⟦⟧-mon κ (⟦$⟧ ↘f ↘a ↘A)                                         = ⟦$⟧ (⟦⟧-mon κ ↘f) (⟦⟧-mon κ ↘a) (∙-mon κ ↘A)
  ⟦⟧-mon {box t} {ρ} {box A} κ (⟦box⟧ ↘A)                         = ⟦box⟧ (subst (⟦ t ⟧_↘ A [ ins κ 1 ]) (ext-mon ρ 1 (ins κ 1)) (⟦⟧-mon (ins κ 1) ↘A))
  ⟦⟧-mon {unbox .n t} {ρ} {A} κ (⟦unbox⟧ {_} {_} {a} n ↘a unbox↘) = ⟦unbox⟧ n
                                                                            (subst (⟦ t ⟧_↘ a [ κ ∥ O ρ n ]) (sym (ρ-∥-[] ρ κ n)) (⟦⟧-mon (κ ∥ O ρ n) ↘a))
                                                                            (subst (unbox∙_, a [ κ ∥ O ρ n ] ↘ A [ κ ]) (sym (O-ρ-[] ρ κ n)) (unbox-mon-⇒ κ unbox↘))
  ⟦⟧-mon κ (⟦[]⟧ ↘ρ′ ↘A)                                          = ⟦[]⟧ (⟦⟧s-mon κ ↘ρ′) (⟦⟧-mon κ ↘A)
  ⟦⟧s-mon : (κ : UMoT) → ⟦ σ ⟧s ρ ↘ ρ′ → ⟦ σ ⟧s ρ [ κ ] ↘ ρ′ [ κ ]
  ⟦⟧s-mon κ ⟦I⟧                                  = ⟦I⟧
  ⟦⟧s-mon {_} {ρ} κ ⟦wk⟧                         = subst (⟦ wk ⟧s ρ [ κ ] ↘_) (sym (drop-mon ρ κ)) ⟦wk⟧
  ⟦⟧s-mon {σ , t} {ρ} κ (⟦,⟧ ↘ρ′ ↘a)             = subst (⟦ σ , t ⟧s ρ [ κ ] ↘_) (sym (↦-mon _ _ κ)) (⟦,⟧ (⟦⟧s-mon κ ↘ρ′) (⟦⟧-mon κ ↘a))
  ⟦⟧s-mon {σ ; n} {ρ} κ (⟦;⟧ {_} {_} {ρ′} ↘ρ′) = subst (⟦ σ ; n ⟧s ρ [ κ ] ↘_)
                                                          (trans (cong (ext _) (O-ρ-[] ρ κ n)) (sym (ext-mon ρ′ (O ρ n) κ)))
                                                          (⟦;⟧ (subst (⟦ σ ⟧s_↘ ρ′ [ κ ∥ O ρ n ]) (sym (ρ-∥-[] ρ κ n)) (⟦⟧s-mon (κ ∥ O ρ n) ↘ρ′)))
  ⟦⟧s-mon κ (⟦∘⟧ ↘ρ″ ↘ρ′)                        = ⟦∘⟧ (⟦⟧s-mon κ ↘ρ″) (⟦⟧s-mon κ ↘ρ′)
  ∙-mon : ∀ {fa} → (κ : UMoT) → f ∙ a ↘ fa → f [ κ ] ∙ a [ κ ] ↘ fa [ κ ]
  ∙-mon {_} {a} {fa} κ (Λ∙ {t} {ρ} ↘fa) = Λ∙ (subst (⟦ t ⟧_↘ fa [ κ ]) (↦-mon ρ a κ) (⟦⟧-mon κ ↘fa))
  ∙-mon κ ($∙ {T} {ρ} {a} {B} A c ↘B)   = $∙ (A [ κ ]) (c [ κ ]) (subst (⟦ T ⟧_↘ B [ κ ]) (↦-mon ρ a κ) (⟦⟧-mon κ ↘B))
  rec-mon : (κ : UMoT) → rec∙ T , a , r , ρ , b ↘ A → rec∙ T , a [ κ ] , r , ρ [ κ ] , b [ κ ] ↘ A [ κ ]
  rec-mon κ ze↘ = ze↘
  rec-mon {r = r} {A = A} κ (su↘ {ρ = ρ} {b} {b′} rec↘ ↘A) = su↘ (rec-mon κ rec↘) (subst (⟦ r ⟧_↘ A [ κ ]) (trans (↦-mon (ρ ↦ b) b′ κ) (cong (_↦ b′ [ κ ]) (↦-mon ρ b κ))) (⟦⟧-mon κ ↘A))
  rec-mon κ (rec∙ {T} {ρ} {c} {A} ↘A) = rec∙ (subst (⟦ T ⟧_↘ A [ κ ]) (↦-mon ρ (↑ N c) κ) (⟦⟧-mon κ ↘A))