------------------------------------------------------------------------
-- The logical relation is clsoed under reduction (in both directions).
------------------------------------------------------------------------

open import Definition.Typed.Restrictions
open import Graded.Erasure.LogicalRelation.Assumptions
open import Graded.Modality

module Graded.Erasure.LogicalRelation.Reduction
  {a} {M : Set a}
  {š•„ : Modality M}
  {R : Type-restrictions š•„}
  (as : Assumptions R)
  where

open Assumptions as
open Modality š•„
open Type-restrictions R

open import Definition.LogicalRelation.Simplified R

open import Definition.Untyped M as U
open import Definition.Untyped.Whnf M type-variant
open import Definition.Typed R
open import Definition.Typed.Properties R

open import Definition.Untyped.Properties M as UP using (wk-id ; wk-lift-id)

open import Graded.Erasure.Extraction.Properties š•„
open import Graded.Erasure.LogicalRelation as
open import Graded.Erasure.Target as T hiding (_⊢_⇒_; _⊢_⇒*_)
open import Graded.Erasure.Target.Properties as TP
open import Graded.Erasure.Target.Reasoning

open import Tools.Function
open import Tools.Nat
open import Tools.Product as Σ
import Tools.PropositionalEquality as PE
open import Tools.Relation
open import Tools.Sum using (inj₁; injā‚‚)

private
  variable
    n : Nat
    t t′ A : U.Term n
    v v′ : T.Term n
    Ī“ : U.Con U.Term n

opaque

  -- The logical relation for erasure is preserved by backward
  -- "reduction" for the source term.

  sourceRedSubstTerm :
    ([A] : ts Ā» Ī” ⊨ A) →
    t′ Ā® v ∷ A / [A] →
    t ⇛ t′ ∷ A →
    t ® v ∷ A / [A]
  sourceRedSubstTerm (Levelįµ£ _) (U/Levelįµ£ ⇒*↯) _ =
    U/Levelįµ£ ⇒*↯
  sourceRedSubstTerm (Uįµ£ _) (U/Levelįµ£ ⇒*↯) _ =
    U/Levelįµ£ ⇒*↯
  sourceRedSubstTerm (Liftᵣ′ ⇒*Lift ⊩A) t′®v t⇛t′ =
    sourceRedSubstTerm ⊩A t′®v (lower-⇛ (conv-⇛ t⇛t′ (subset* ⇒*Lift)))
  sourceRedSubstTerm (ā„•įµ£ D) (zeroįµ£ t′⇒zero v⇒v′) t⇒t′ =
    zeroįµ£ (trans-⇛ (conv-⇛ t⇒t′ (subset* D)) t′⇒zero) v⇒v′
  sourceRedSubstTerm (ā„•įµ£ ⇒*ā„•) (sucįµ£ t′⇒suc v⇒v′ num tĀ®v) t⇒t′ =
    sucįµ£ (trans-⇛ (conv-⇛ t⇒t′ (subset* ⇒*ā„•)) t′⇒suc) v⇒v′ num tĀ®v
  sourceRedSubstTerm (Unitįµ£ D) (starįµ£ t′⇒star v⇒star) t⇒t′ =
    starįµ£ (trans-⇛ (conv-⇛ t⇒t′ (subset* D)) t′⇒star) v⇒star
  sourceRedSubstTerm (Bᵣ′ BMĪ  p q F G D [F] [G]) tĀ®v t⇒t′
    with is-šŸ˜? p
  ... | yes PE.refl = tĀ®v .proj₁ , Ī» {a = a} ⊢a →
    sourceRedSubstTerm ([G] ⊢a) (tĀ®v .projā‚‚ ⊢a)
      (app-⇛ (conv-⇛ t⇒t′ (subset* D)) ⊢a)
  ... | no pā‰¢šŸ˜ = tĀ®v .proj₁ , Ī» {a = a} ⊢a aĀ®w →
    sourceRedSubstTerm ([G] ⊢a) (tĀ®v .projā‚‚ ⊢a aĀ®w)
      (app-⇛ (conv-⇛ t⇒t′ (subset* D)) ⊢a)
  sourceRedSubstTerm
    (Bᵣ′ (BMĪ£ _) _ _ F G D [F] [G])
    (t₁ , tā‚‚ , t′⇒p , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚ , extra) t⇒t′ =
    t₁ , tā‚‚ , trans-⇛ (conv-⇛ t⇒t′ (subset* D)) t′⇒p , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚ ,
    extra
  sourceRedSubstTerm (Idįµ£ ⊩A) (rflįµ£ t′⇒*rfl ⇒*↯) t⇒t′ =
    rflįµ£ (trans-⇛ (conv-⇛ t⇒t′ (subset* (_⊨Id_.⇒*Id ⊩A))) t′⇒*rfl) ⇒*↯
  sourceRedSubstTerm (ne record{}) ()
  sourceRedSubstTerm (Emptyįµ£ _)    ()

opaque

  -- Logical relation for erasure is preserved under a single reduction backwards on the target language term
  --
  -- Proof by induction on t Ā® v′ ∷ A

  targetRedSubstTerm :
    ([A] : ts Ā» Ī” ⊨ A) →
    t Ā® v′ ∷ A / [A] →
    vs T.⊢ v ⇒ v′ →
    t ® v ∷ A / [A]
  targetRedSubstTerm (Levelįµ£ _) (U/Levelįµ£ ⇒*↯) v⇒v′ =
    U/Levelįµ£ (T.trans v⇒v′ āˆ˜ā†’ ⇒*↯)
  targetRedSubstTerm (Uįµ£ _) (U/Levelįµ£ ⇒*↯) v⇒v′ =
    U/Levelįµ£ (T.trans v⇒v′ āˆ˜ā†’ ⇒*↯)
  targetRedSubstTerm (Liftᵣ′ _ ⊩A) tĀ®v′ v⇒v′ =
    targetRedSubstTerm ⊩A tĀ®v′ v⇒v′
  targetRedSubstTerm (ā„•įµ£ x) (zeroįµ£ t′⇒zero v′⇒zero) v⇒v′ = zeroįµ£ t′⇒zero (trans v⇒v′ v′⇒zero)
  targetRedSubstTerm (ā„•įµ£ _) (sucįµ£ t′⇒suc v′⇒suc num tĀ®v) v⇒v′ =
    sucįµ£ t′⇒suc (trans v⇒v′ v′⇒suc) num tĀ®v
  targetRedSubstTerm (Unitįµ£ x) (starįµ£ x₁ v′⇒star) v⇒v′ = starįµ£ x₁ (trans v⇒v′ v′⇒star)
  targetRedSubstTerm
    (Bᵣ′ BMĪ  p q F G D [F] [G]) (v′⇒*lam , tĀ®v) v⇒v′
    with is-šŸ˜? p | Ī£.map idį¶  (T.trans v⇒v′) āˆ˜ā†’ v′⇒*lam
  ... | yes PE.refl | v⇒*lam = v⇒*lam , Ī» ⊢a →
    targetRedSubstTerm ([G] ⊢a) (tĀ®v ⊢a) (app-šŸ˜ā€²-subst v⇒v′)
  ... | no pā‰¢šŸ˜ | v⇒*lam = v⇒*lam , Ī» ⊢a aĀ®w →
    targetRedSubstTerm ([G] ⊢a) (tĀ®v ⊢a aĀ®w) (app-subst v⇒v′)
  targetRedSubstTerm {A = A} {t = t} {v = v}
    [Ī£]@(Bᵣ′ (BMĪ£ _) p _ F G D [F] [G])
    (t₁ , tā‚‚ , t⇒t′ , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚ , extra) v⇒v′ =
      t₁ , tā‚‚ , t⇒t′ , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚
         , Ī£-Ā®-elim (Ī» _ → Ī£-Ā® F [F] t₁ v vā‚‚ p) extra
               (Ī» v′⇒vā‚‚         → Ī£-Ā®-intro-šŸ˜ (trans v⇒v′ v′⇒vā‚‚))
               (Ī» v₁ v′⇒p t₁®v₁ → Ī£-Ā®-intro-ω v₁ (trans v⇒v′ v′⇒p) t₁®v₁)
  targetRedSubstTerm (Idįµ£ _) (rflįµ£ t⇒*rfl ⇒*↯) v⇒v′ =
    rflįµ£ t⇒*rfl (T.trans v⇒v′ āˆ˜ā†’ ⇒*↯)
  targetRedSubstTerm (ne record{}) ()
  targetRedSubstTerm (Emptyįµ£ _)    ()

opaque

  -- Logical relation for erasure is preserved under reduction closure backwards
  -- on the target language term.
  --
  -- Proof by induction on t Ā® v′ ∷ A

  targetRedSubstTerm* :
    ([A] : ts Ā» Ī” ⊨ A) →
    t Ā® v′ ∷ A / [A] →
    vs T.⊢ v ⇒* v′ →
    t ® v ∷ A / [A]
  targetRedSubstTerm* [A] tĀ®v′ refl = tĀ®v′
  targetRedSubstTerm* [A] tĀ®v′ (trans x v⇒v′) =
    targetRedSubstTerm [A] (targetRedSubstTerm* [A] tĀ®v′ v⇒v′) x

opaque

  -- The logical relation for erasure is preserved by backward
  -- "reduction" for the source term and backward reduction for the
  -- target term.

  redSubstTerm :
    ([A] : ts Ā» Ī” ⊨ A) →
    t′ Ā® v′ ∷ A / [A] →
    t ⇛ t′ ∷ A →
    vs T.⊢ v ⇒ v′ →
    t ® v ∷ A / [A]
  redSubstTerm [A] t′®v′ t⇒t′ v⇒v′ =
    targetRedSubstTerm [A] (sourceRedSubstTerm [A] t′®v′ t⇒t′) v⇒v′

opaque

  -- The logical relation for erasure is preserved by backward
  -- "reduction" for the source term and backward reduction for the
  -- target term.

  redSubstTerm* :
    ([A] : ts Ā» Ī” ⊨ A) →
    t′ Ā® v′ ∷ A / [A] →
    t ⇛ t′ ∷ A →
    vs T.⊢ v ⇒* v′ →
    t ® v ∷ A / [A]
  redSubstTerm* [A] t′®v′ t⇒t′ v⇒v′ =
    targetRedSubstTerm* [A] (sourceRedSubstTerm [A] t′®v′ t⇒t′) v⇒v′

opaque

  -- The logical relation for erasure is preserved by "reduction" for
  -- the source term.

  sourceRedSubstTerm′ :
    ([A] : ts Ā» Ī” ⊨ A) →
    t Ā® v ∷ A / [A] →
    t ⇛ t′ ∷ A →
    t′ Ā® v ∷ A / [A]
  sourceRedSubstTerm′ (Levelįµ£ _) (U/Levelįµ£ ⇒*↯) _ =
    U/Levelįµ£ ⇒*↯
  sourceRedSubstTerm′ (Uįµ£ _) (U/Levelįµ£ ⇒*↯) _ =
    U/Levelįµ£ ⇒*↯
  sourceRedSubstTerm′ (Liftᵣ′ ⇒*Lift ⊩A) tĀ®v t⇛t′ =
    sourceRedSubstTerm′ ⊩A tĀ®v (lower-⇛ (conv-⇛ t⇛t′ (subset* ⇒*Lift)))
  sourceRedSubstTerm′ (ā„•įµ£ D) (zeroįµ£ t⇒zero v⇒zero) t⇒t′
    with whnf-⇛ t⇒zero zeroā‚™ (conv-⇛ t⇒t′ (subset* D))
  ... | t′⇒zero = zeroįµ£ t′⇒zero v⇒zero
  sourceRedSubstTerm′ (ā„•įµ£ D) (sucįµ£ t⇒suc v⇒suc num tĀ®v) t⇒t′
    with whnf-⇛ t⇒suc sucā‚™ (conv-⇛ t⇒t′ (subset* D))
  ... | t′⇒suc = sucįµ£ t′⇒suc v⇒suc num tĀ®v
  sourceRedSubstTerm′ (Unitįµ£ x) (starįµ£ t⇒star v⇒star) t⇒t′
    with whnf-⇛ t⇒star starā‚™ (conv-⇛ t⇒t′ (subset* x))
  ... | t′⇒star = starįµ£ t′⇒star v⇒star
  sourceRedSubstTerm′
    (Bᵣ′ BMĪ  p q F G D [F] [G]) tĀ®v t⇒t′
    with is-šŸ˜? p
  ... | yes PE.refl = tĀ®v .proj₁ , Ī» ⊢a →
    sourceRedSubstTerm′ ([G] ⊢a) (tĀ®v .projā‚‚ ⊢a)
      (app-⇛ (conv-⇛ t⇒t′ (subset* D)) ⊢a)
  ... | no pā‰¢šŸ˜ = tĀ®v .proj₁ , Ī» {a = a} ⊢a aĀ®w →
    sourceRedSubstTerm′ ([G] ⊢a) (tĀ®v .projā‚‚ ⊢a aĀ®w)
      (app-⇛ (conv-⇛ t⇒t′ (subset* D)) ⊢a)
  sourceRedSubstTerm′
    (Bᵣ′ (BMĪ£ _) _ _ F G D [F] [G])
    (t₁ , tā‚‚ , t⇒p , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚ , extra) t⇒t′ =
    t₁ , tā‚‚
       , whnf-⇛ t⇒p prodā‚™ (conv-⇛ t⇒t′ (subset* D))
       , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚ , extra
  sourceRedSubstTerm′ (Idįµ£ ⊩A) (rflįµ£ t⇒*rfl ⇒*↯) t⇒t′ =
    rflįµ£ (whnf-⇛ t⇒*rfl rflā‚™ (conv-⇛ t⇒t′ (subset* (_⊨Id_.⇒*Id ⊩A)))) ⇒*↯
  sourceRedSubstTerm′ (ne record{}) ()
  sourceRedSubstTerm′ (Emptyįµ£ _)    ()


private opaque

  -- Some lemmas used below.

  Ī -lemma :
    vs T.⊢ v ⇒ v′ →
    (∃ Ī» v″ → vs T.⊢ v ⇒* T.lam v″) →
    (∃ Ī» v″ → vs T.⊢ v′ ⇒* T.lam v″)
  Ī -lemma v⇒v′ (_ , v⇒*lam)
    with red*Det v⇒*lam (T.trans v⇒v′ T.refl)
  … | inj₁ lam⇒*v′ rewrite Value→⇒*→≔ T.lam lam⇒*v′ = _ , T.refl
  … | injā‚‚ v′⇒*lam = _ , v′⇒*lam

  ⇒*↯→⇒→⇒*↯ :
    (str PE.≔ strict → vs T.⊢ v ⇒* ↯) → vs T.⊢ v ⇒ v′ →
    str PE.≔ strict → vs T.⊢ v′ ⇒* ↯
  ⇒*↯→⇒→⇒*↯ {v′} v⇒*↯ v⇒v′ ≔strict =
    case red*Det (v⇒*↯ ≔strict) (T.trans v⇒v′ T.refl) of Ī» where
      (injā‚‚ v′⇒*↯) → v′⇒*↯
      (inj₁ ↯⇒*v′) →
        v′  ā‰”āŸØ ↯-noRed ↯⇒*v′ āŸ©ā‡’
        ↯   āˆŽā‡’

opaque

  -- The logical relation for erasure is preserved under reduction of
  -- the target language term.

  targetRedSubstTerm*′ :
    ([A] : ts Ā» Ī” ⊨ A) → t Ā® v ∷ A / [A] →
    vs T.⊢ v ⇒* v′ → t Ā® v′ ∷ A / [A]

  -- Logical relation for erasure is preserved under one reduction step on the target language term
  -- If t Ā® v ∷ A and v ⇒ v′  then t Ā® v′ ∷ A
  --
  -- Proof by induction on t ® v ∷ A

  targetRedSubstTerm′ : ([A] : ts Ā» Ī” ⊨ A) → t Ā® v ∷ A / [A]
                      → vs T.⊢ v ⇒ v′ → t Ā® v′ ∷ A / [A]
  targetRedSubstTerm′ (Levelįµ£ _) (U/Levelįµ£ v⇒*↯) v⇒v′ =
    U/Levelįµ£ (⇒*↯→⇒→⇒*↯ v⇒*↯ v⇒v′)
  targetRedSubstTerm′ (Uįµ£ _) (U/Levelįµ£ v⇒*↯) v⇒v′ =
    U/Levelįµ£ (⇒*↯→⇒→⇒*↯ v⇒*↯ v⇒v′)
  targetRedSubstTerm′ (Liftᵣ′ _ ⊩A) tĀ®v v⇒v′ =
    targetRedSubstTerm′ ⊩A tĀ®v v⇒v′
  targetRedSubstTerm′ (ā„•įµ£ x) (zeroįµ£ x₁ v⇒zero) v⇒v′ with red*Det v⇒zero (T.trans v⇒v′ T.refl)
  ... | inj₁ xā‚‚ rewrite zero-noRed xā‚‚ = zeroįµ£ x₁ T.refl
  ... | injā‚‚ xā‚‚ = zeroįµ£ x₁ xā‚‚
  targetRedSubstTerm′ (ā„•įµ£ _) (sucįµ£ t⇒suc v⇒suc num tĀ®v) v⇒v′
    with red*Det v⇒suc (T.trans v⇒v′ T.refl)
  ... | inj₁ suc⇒* rewrite suc-noRed suc⇒* = sucįµ£ t⇒suc T.refl num tĀ®v
  ... | injā‚‚ ⇒*suc = sucįµ£ t⇒suc ⇒*suc num tĀ®v
  targetRedSubstTerm′ (Unitįµ£ x) (starįµ£ x₁ v⇒star) v⇒v′ with red*Det v⇒star (T.trans v⇒v′ T.refl)
  ... | inj₁ xā‚‚ rewrite star-noRed xā‚‚ = starįµ£ x₁ T.refl
  ... | injā‚‚ xā‚‚ = starįµ£ x₁ xā‚‚
  targetRedSubstTerm′
    (Bᵣ′ BMĪ  p q F G D [F] [G]) tĀ®v v⇒v′
    with is-šŸ˜? p
  ... | yes PE.refl = Ī -lemma v⇒v′ āˆ˜ā†’ tĀ®v .proj₁ , Ī» ⊢a →
    targetRedSubstTerm′ ([G] ⊢a) (tĀ®v .projā‚‚ ⊢a) (app-šŸ˜ā€²-subst v⇒v′)
  ... | no pā‰¢šŸ˜ = Ī -lemma v⇒v′ āˆ˜ā†’ tĀ®v .proj₁ , Ī» ⊢a aĀ®w →
    targetRedSubstTerm′ ([G] ⊢a) (tĀ®v .projā‚‚ ⊢a aĀ®w) (T.app-subst v⇒v′)
  targetRedSubstTerm′
    {v′ = v′}
    (Bᵣ′ (BMĪ£ _) p _ F G D [F] [G])
    (t₁ , tā‚‚ , t⇒t′ , ⊢t₁ , vā‚‚ , tā‚‚Ā®vā‚‚ , extra) v⇒v′ =
    let [Gt₁] = [G] ⊢t₁
    in  t₁ , tā‚‚ , t⇒t′ , ⊢t₁
        , Σ-®-elim
           (Ī» _ → ∃ Ī» vā‚‚ → (tā‚‚ Ā® vā‚‚ ∷ G U.[ t₁ ]ā‚€ / [Gt₁])
                         Ɨ Ī£-Ā® F _ t₁ v′ vā‚‚ p)
           extra
           (Ī» v⇒vā‚‚ pā‰”šŸ˜ → case red*Det v⇒vā‚‚ (trans v⇒v′ refl) of Ī» where
             (inj₁ v₂⇒v′) → v′ , targetRedSubstTerm*′ [Gt₁] tā‚‚Ā®vā‚‚ v₂⇒v′
                               , Ī£-Ā®-intro-šŸ˜ refl pā‰”šŸ˜
             (injā‚‚ v′⇒vā‚‚) → vā‚‚ , tā‚‚Ā®vā‚‚ , Ī£-Ā®-intro-šŸ˜ v′⇒vā‚‚ pā‰”šŸ˜)
           Ī» v₁ v⇒p t₁®v₁ pā‰¢šŸ˜ → vā‚‚ , tā‚‚Ā®vā‚‚ , (case red*Det v⇒p (trans v⇒v′ refl) of Ī» where
             (inj₁ p⇒v′) → case prod-noRed p⇒v′ of Ī» where
               PE.refl → Ī£-Ā®-intro-ω v₁ refl t₁®v₁ pā‰¢šŸ˜
             (injā‚‚ v′⇒p) → Ī£-Ā®-intro-ω v₁ v′⇒p t₁®v₁ pā‰¢šŸ˜)

  targetRedSubstTerm′ (Idįµ£ _) (rflįµ£ t⇒*rfl v⇒*↯) v⇒v′ =
    rflįµ£ t⇒*rfl (⇒*↯→⇒→⇒*↯ v⇒*↯ v⇒v′)
  targetRedSubstTerm′ (ne record{}) ()
  targetRedSubstTerm′ (Emptyįµ£ _)    ()


  targetRedSubstTerm*′ [A] tĀ®v refl = tĀ®v
  targetRedSubstTerm*′ [A] tĀ®v (trans x v⇒v′) =
    targetRedSubstTerm*′ [A] (targetRedSubstTerm′ [A] tĀ®v x) v⇒v′

opaque

  -- The logical relation for erasure is preserved by "reduction" for
  -- the source term and reduction for the target term.

  redSubstTerm′ :
    ([A] : ts Ā» Ī” ⊨ A) →
    t Ā® v ∷ A / [A] →
    t ⇛ t′ ∷ A →
    vs T.⊢ v ⇒ v′ →
    t′ Ā® v′ ∷ A / [A]
  redSubstTerm′ [A] tĀ®v t⇒t′ v⇒v′ =
    targetRedSubstTerm′ [A] (sourceRedSubstTerm′ [A] tĀ®v t⇒t′) v⇒v′

opaque

  -- The logical relation for erasure is preserved by "reduction" for
  -- the source term and reduction for the target term.

  redSubstTerm*′ :
    ([A] : ts Ā» Ī” ⊨ A) →
    t Ā® v ∷ A / [A] →
    t ⇛ t′ ∷ A →
    vs T.⊢ v ⇒* v′ →
    t′ Ā® v′ ∷ A / [A]
  redSubstTerm*′ [A] tĀ®v t⇒t′ v⇒v′ =
    targetRedSubstTerm*′ [A] (sourceRedSubstTerm′ [A] tĀ®v t⇒t′) v⇒v′