module GST.ReifyReflect where

open import Prelude
open import WSLN

open import GST.Syntax
open import GST.Context
open import GST.TypeSystem
open import GST.WellScoped
open import GST.Setoid
open import GST.Renaming
open import GST.Substitution
open import GST.Admissible
open import GST.UniqueTypes
open import GST.NormalForm
open import GST.Presheaf
open import GST.TypeSemantics

----------------------------------------------------------------------
-- Reification and reflection
----------------------------------------------------------------------
โ†“ : (A : Ty) โ†’ โ„^[ ๐““ A โŸถ Norm A ]

โ†‘ : (A : Ty) โ†’ โ„^[ Neut A โŸถ ๐““ A ]

โ†“โ‚€ : (A : Ty){ฮ“ : Cx} โ†’ โˆฃ ๐““ A โŠ™ ฮ“ โˆฃ โ†’ Tm
โ†“โ‚€ A ๐“ช = nt (hom (โ†“ A) โ‚€ ๐“ช)

โ†“โ‚€โŠข : {A : Ty}{ฮ“ : Cx}(๐“ช : โˆฃ ๐““ A โŠ™ ฮ“ โˆฃ) โ†’ ฮ“ โŠขโฟ โ†“โ‚€ A ๐“ช โˆถ A
โ†“โ‚€โŠข ๐“ช = pf (hom (โ†“ _) โ‚€ ๐“ช)

โ†‘โ‚€ : {A : Ty}{a : Tm}{ฮ“ : Cx} โ†’ ( ฮ“ โŠขแต˜ a โˆถ A) โ†’ โˆฃ ๐““ A โŠ™ ฮ“ โˆฃ
โ†‘โ‚€ q = hom (โ†‘ _) โ‚€ mkโˆฃNeutโˆฃ _ q

module reify
  (A B : Ty)
  (ฮ“ : Cx)
  (x : ๐”ธ)
  โฆƒ _  : x # ฮ“ โฆ„
  where
  ฮ“x : Cx
  ฮ“x = ฮ“ โจŸ x โˆถ A

  ๐” : โˆฃ ๐““ A โŠ™ ฮ“x โˆฃ
  ๐” = hom (โ†‘ A) โ‚€ newvar x A

  module _ (ฯ† : โ„^[ ใ‚ˆ ฮ“ ร—^ ๐““ A โŸถ ๐““ B ]) where
    ๐“ซ : โˆฃ ๐““ B โŠ™ ฮ“x โˆฃ
    ๐“ซ = hom ฯ† โ‚€ (proj A , ๐”)

    โ†“๐“ซ : Tm
    โ†“๐“ซ = โ†“โ‚€ B ๐“ซ

    n : โˆฃ Norm (A โ‡’ B) โŠ™ ฮ“ โˆฃ
    nt n = ๐›Œ A (x ๏ผŽ โ†“๐“ซ)
    pf n = Lam {x = x}
      (subst (ฮป c โ†’  ฮ“ โจŸ x โˆถ A โŠขโฟ c โˆถ B)
        (symm (concAbs' x โ†“๐“ซ))
        (โ†“โ‚€โŠข ๐“ซ))
      (#abs x โ†“๐“ซ)

โ†“ ๐๐š๐ญ = id

hom (โ†“ (A โ‡’ B)) {ฮ“} = mkSetd[โŸถ]
  (reify.n  A B ฮ“ x)
  (ฮป f โ†’ cong (ฮป c โ†’ ๐›Œ A (x ๏ผŽ c))
    (hom (โ†“ B) โ‚ f (proj A , reify.๐” A B ฮ“ x)))
  where
  x = new (supp ฮ“)
  instance
   _ : x # ฮ“
   _ = newโˆ‰ (supp ฮ“)

ntl (โ†“ (A โ‡’ B)) {ฮ“} {ฮ“'} p ฯ† = k
  where
  x x' : ๐”ธ
  x = new (supp ฮ“)
  x' = new (supp ฮ“')
  instance
    _ : x # ฮ“
    _ = newโˆ‰ (supp ฮ“)
    _ : x' # ฮ“'
    _ = newโˆ‰ (supp ฮ“')

  open reify A B ฮ“ x
  open reify A B ฮ“' x'
    renaming (ฮ“x to ฮ“x' ; ๐” to ๐”' ; ๐“ซ to ๐“ซ' ; โ†“๐“ซ to โ†“๐“ซ')

  p' : โ„[ ฮ“x' โŸถ ฮ“x ]
  rn p' = rn p โˆ˜/ x := x'
  pf p' = liftRn (pf p)

  e' : Rn[  ฮ“ ] โˆ‹ rn p ~ (rn p โˆ˜/ x := x')
  e' y yโˆˆฮ“ with x โ‰ y
  ... | no _ = refl
  ... | equ = ร˜elim (โˆ‰โ†’ยฌโˆˆ it yโˆˆฮ“)

  p'๐” : ๐““ A โŠ™ ฮ“x' โˆ‹ ๐”' ~ (๐““ A โŠ™โ€ฒ p') โ‚€ ๐”
  p'๐” = ~Trans (๐““ A โŠ™ ฮ“x')
      (~Symm (๐““ A โŠ™ ฮ“x')
        (hom (โ†‘ A) โ‚ cong ๐ฏ (:=Eq{f = rn p}{x'} x)))
      (ntl (โ†‘ A) p' (newvar x A))

  ๐“ฎ : ๐““ B โŠ™ ฮ“x' โˆ‹ hom ฯ† โ‚€ (p โˆ˜แตฃ proj A , ๐”') ~
    ๐““ B โŠ™โ€ฒ p' โ‚€ (hom ฯ† โ‚€ (proj A , ๐”))
  ๐“ฎ = ~Trans (๐““ B โŠ™ ฮ“x')
    (hom ฯ† โ‚ (e' , p'๐”))
    (ntl ฯ† p' (proj A , ๐”))

  t t' : Tm
  t = โ†“โ‚€ B (hom ฯ† โ‚€ (proj A , ๐”))
  t' = โ†“โ‚€ B (hom ฯ† โ‚€ (p โˆ˜แตฃ proj A , ๐”'))

  k' : t' โ‰ก (rn p โˆ˜/ x := x') * t
  k' =
    begin
      โ†“โ‚€ B (hom ฯ† โ‚€ (p โˆ˜แตฃ proj A , ๐”'))
    โ‰กโŸจ hom (โ†“ B) โ‚ ๐“ฎ โŸฉ
      โ†“โ‚€ B ((๐““ B โŠ™โ€ฒ p') โ‚€ hom ฯ† โ‚€ (proj A , ๐”))
    โ‰กโŸจ ntl (โ†“ B) p' (hom ฯ† โ‚€ (proj A , ๐”)) โŸฉ
      (rn p โˆ˜/ x := x') * t
    โˆŽ

  k :  ๐›Œ A (x' ๏ผŽ t') โ‰ก rn p * ๐›Œ A (x ๏ผŽ t)
  k =
    begin
      ๐›Œ A (x' ๏ผŽ t')
    โ‰กโŸจ cong (ฮป c โ†’ ๐›Œ A (x' ๏ผŽ c)) k' โŸฉ
       ๐›Œ A (x' ๏ผŽ (rn p โˆ˜/ x := x') * t)
    โ‰กห˜โŸจ cong (๐›Œ A) (rnAbs (rn p) x x'
      (โ†“โ‚€ B (hom ฯ† โ‚€ (proj A , ๐”)))
      ฮป y ya yx e โ†’ โˆ‰โ†’ยฌโˆˆ it
        (subst (_โˆˆ dom ( ฮ“')) (symm e)
        (rnDom (pf p)
          (โˆˆโˆ‰โ‚ (suppโŠข
            (tyโฟ (โ†“โ‚€โŠข{B} (hom ฯ† โ‚€ (proj A , ๐”)))) ya)
            (โˆ‰๏ฝ›๏ฝ(โ‰ ๐”ธsymm (โ‰ขโ†’โ‰ ๐”ธ yx))))))) โŸฉ
      rn p * ๐›Œ A (x ๏ผŽ t)
    โˆŽ

โ†‘ ๐๐š๐ญ = neu

hom (hom (โ†‘ (A โ‡’ B)) โ‚€ mkโˆฃNeutโˆฃ a q) โ‚€ (p , ๐“ช) = hom (โ†‘ B) โ‚€
  mkโˆฃNeutโˆฃ
    ((rn p * a) โˆ™ โ†“โ‚€ A ๐“ช)
    (App (rnโŠขแต˜ (pf p) q) (pf (hom (โ†“ A) โ‚€ ๐“ช)))

hom (hom (โ†‘ (A โ‡’ B)) โ‚€ mkโˆฃNeutโˆฃ a q) โ‚ (e , e') = hom (โ†‘ B) โ‚
  congโ‚‚ _โˆ™_
    (rnRespSupp _ _ a (ฮป x r โ†’ e x (suppโŠข (tyแต˜ q) r)))
    (hom (โ†“ A) โ‚ e')

ntl (hom (โ†‘ (A โ‡’ B)) โ‚€ mkโˆฃNeutโˆฃ a q) {_}{ฮ“''} p' (p , ๐“ช) =
  ~Trans (๐““ B โŠ™ ฮ“'')
    (hom (โ†‘ B) โ‚ congโ‚‚ _โˆ™_
      (rnAssoc (rn p) (rn p') a)
      (ntl (โ†“ A) p' ๐“ช))
    (ntl (โ†‘ B) p' (mkโˆฃNeutโˆฃ
      ((rn p * a) โˆ™ โ†“โ‚€ A ๐“ช)
      (App (rnโŠขแต˜ (pf p) q) (pf (hom (โ†“ A) โ‚€ ๐“ช)))))

(hom (โ†‘ (_ โ‡’ B)) โ‚ refl) (_ , _) = hom (โ†‘ B) โ‚ refl


ntl (โ†‘ (A โ‡’ B)) {ฮ“} {ฮ“'} p' a {ฮ“''} (p , ๐“ช) = hom (โ†‘ B) โ‚
  cong (ฮป c โ†’ c โˆ™ nt (hom (โ†“ A) โ‚€ ๐“ช))
    (symm (rnAssoc (rn p') (rn p) (ut a)))

----------------------------------------------------------------------
-- Initial environment
----------------------------------------------------------------------
๐“ผโ‚€ : โˆ€ ฮ“ โ†’ โˆฃ ๐“” ฮ“ โŠ™ ฮ“ โˆฃ

๐“ผโ‚€ โ—‡ = tt
๐“ผโ‚€ (ฮ“ โจŸ _ โˆถ A) =
  (๐“” ฮ“ โŠ™โ€ฒ proj A โ‚€ ๐“ผโ‚€ ฮ“ , โ†‘โ‚€{A} (Var (isInNew refl)))