{-# OPTIONS --safe #-}
module Splice.Translate where

open import Data.Nat.Base using (; zero; suc; _≥‴_; ≤‴-refl; ≤‴-step)
open import Relation.Binary.PropositionalEquality.Core using (_≡_; refl; cong; subst)

import Splice.Context as S
import Splice.Term as S
import CtxTyp.Context as C
import CtxTyp.Term as C

variable
  n m n′ m′ n″ m″ : 
  m≥n m′≥n : m ≥‴ n

◯^ : m ≥‴ n  S.Type m  S.Type n
◯^ ≤‴-refl A = A
◯^ (≤‴-step m≥n) A = S.◯ (◯^ m≥n A)

infixr 7 _^_⇛_ _⇛₀_ _⇛₁_

_^_⇛_ : C.Context m  m ≥‴ n  S.Type n  S.Type n
⟦_⟧ᵗ : C.Type n  S.Type n

_⇛₀_ : C.Context n  S.Type n  S.Type n
Δ ⇛₀ A = Δ ^ ≤‴-refl  A

_⇛₁_ : C.Context (suc n)  S.Type n  S.Type n
Δ ⇛₁ A = _^_⇛_ Δ (≤‴-step ≤‴-refl) A

C.∅ ^ m≥n  A = A
(Γ C.,[ Δ C.⊢ A′ ^ m′≥m ]) ^ m≥n  A = _^_⇛_ Γ m≥n (◯^ m≥n (◯^ m′≥m (Δ ⇛₀  A′ ⟧ᵗ)) S.⇒ A)

 C.[ Δ  A ]⇒ B ⟧ᵗ = (Δ ⇛₁  A ⟧ᵗ) S.⇒  B ⟧ᵗ
 Δ C.▷ A ⟧ᵗ = (Δ ⇛₁  A ⟧ᵗ)
 C.`Bool ⟧ᵗ = S.`Bool
 C.◯ A ⟧ᵗ = S.◯  A ⟧ᵗ

⟦_⟧ᶜ : C.Context n  S.Context
 C.∅ ⟧ᶜ = S.∅   
 Γ C.,[ Δ C.⊢ A ^ m≥n ] ⟧ᶜ =  Γ ⟧ᶜ S., (Δ ⇛₀  A ⟧ᵗ)

⟦_⟧ˣ :  {Γ} {Δ} {A} {m≥n : m ≥‴ n}  Γ C.∋[ Δ C.⊢ A ^ m≥n ]   Γ ⟧ᶜ S.∋ (_^_⇛_ Δ ≤‴-refl  A ⟧ᵗ) ^ _
 C.Z ⟧ˣ = S.Z
 C.S x ⟧ˣ = S.S  x ⟧ˣ

inject₁-⇛₀ :  Δ {A : S.Type n}  C.inject₁ Δ ⇛₀ A  Δ ⇛₁ A
inject₁-⇛₀ C.∅ = refl
inject₁-⇛₀ (Δ C.,[ Δ′ C.⊢ A′ ^ m≥n ]) = inject₁-⇛₀ Δ

⟨_⟩^_ :  {Γ} {A}  S.Term m Γ A  (m≥n : m ≥‴ n)  S.Term n Γ (◯^ m≥n A)
 e ⟩^ ≤‴-refl = e
 e ⟩^ ≤‴-step m≥n = S.⟨  e ⟩^ m≥n 

$^ :  {Γ} {A}  (m≥n : m ≥‴ n)  S.Term n Γ (◯^ m≥n A)  S.Term m Γ A
$^ ≤‴-refl e = e
$^ (≤‴-step m≥n) e = $^ m≥n (S.$ e)

`λλ :  {Γ} Δ {A}   S.Term n  Γ C.++ Δ ⟧ᶜ A  S.Term n  Γ ⟧ᶜ (Δ ⇛₀ A)
`λλ C.∅ e = e
`λλ (Δ C.,[ Δ₁ C.⊢ A ^ m≥n ]) e =  `λλ Δ (S.`λ S.subst  { S.Z  $^ m≥n (S.` S.Z); (S.S x)  S.` S.S x }) e)

`λλ₁ :  {Γ} Δ {A}  S.Term (suc n)  Γ C.++ C.inject₁ Δ ⟧ᶜ A   S.Term (suc n)  Γ ⟧ᶜ (Δ ⇛₀ A) 
`λλ₁ C.∅ e = e
`λλ₁ (Δ C.,[ Δ₁ C.⊢ A ^ m≥n ]) e = `λλ₁ Δ (S.`λ S.subst  { S.Z  $^ m≥n (S.` S.Z); (S.S x)  S.` S.S x }) e)

`λλ◯ :  {Γ} Δ {A}  S.Term n  Γ C.++ C.inject₁ Δ ⟧ᶜ A  S.Term n  Γ ⟧ᶜ (Δ ⇛₁ A)
`λλ◯ C.∅ e = e
`λλ◯ (Δ C.,[ Δ₁ C.⊢ A ^ m≥n ]) e = `λλ◯ Δ (S.`λ S.subst  { S.Z  $^ m≥n (S.$ (S.` S.Z)); (S.S x)  S.` S.S x }) e)

wk↾ :  {Γ : C.Context n}  S.Rename  Γ C.↾ ⟧ᶜ  Γ ⟧ᶜ
wk↾ {Γ = Γ C.,[ Δ C.⊢ A ^ ≤‴-refl ]} x = S.S (wk↾ x)
wk↾ {Γ = Γ C.,[ Δ C.⊢ A ^ ≤‴-step m≥n ]} S.Z = S.Z
wk↾ {Γ = Γ C.,[ Δ C.⊢ A ^ ≤‴-step m≥n ]} (S.S x) = S.S (wk↾ x) 

wk↾≥ :  {Γ : C.Context n}  (m≥n : m ≥‴ n)  S.Rename  Γ C.↾≥ m≥n ⟧ᶜ  Γ ⟧ᶜ
wk↾≥ ≤‴-refl x = x
wk↾≥ (≤‴-step m≥n) x = wk↾ (wk↾≥ m≥n x)

applyTerm :  {Γ} {Δ} {A}  S.Term n  Γ ⟧ᶜ (Δ ⇛₀ A)  Γ C.⊩ Δ  S.Term n  Γ ⟧ᶜ A
⟦_⟧ᵉ :  {Γ} {A}  C.Term n Γ A  S.Term n ( Γ ⟧ᶜ) ( A ⟧ᵗ)

applyTerm e C.∅ = e
applyTerm e (C._,_ {Δ = Δ} {m≥n = m≥n} σ (C.term e′)) = applyTerm e σ S.·  S.rename (wk↾≥ m≥n) (`λλ Δ  e′ ⟧ᵉ) ⟩^ m≥n
applyTerm e (C._,_ {m≥n = m≥n} σ (C.var y)) = applyTerm e σ S.· ( S.`  y ⟧ˣ ⟩^ m≥n)

 C.` x `with σ ⟧ᵉ = applyTerm (S.`  x ⟧ˣ) σ
 C.`true ⟧ᵉ = S.`true
 C.`false ⟧ᵉ = S.`false
 C.`if e₁ `then e₂ `else e₃ ⟧ᵉ = S.`if  e₁ ⟧ᵉ `then  e₂ ⟧ᵉ `else  e₃ ⟧ᵉ
 C.`λ⟨ Δ  e ⟧ᵉ = S.`λ subst  d  (S.Term _ (_ S., d) _)) (inject₁-⇛₀ Δ)  e ⟧ᵉ
 e₁ C.· e₂ ⟧ᵉ =  e₁ ⟧ᵉ  S.· `λλ◯ _  e₂ ⟧ᵉ
 C.⟨ e  ⟧ᵉ = S.⟨ S.rename wk↾  e ⟧ᵉ  
 C.`let⟨ Δ  e₁ e₂ ⟧ᵉ =
  S.`let S.⟨ `λλ₁ Δ (S.$  e₁ ⟧ᵉ)  `in          
  S.subst  {S.Z  S.$ (S.` S.Z); (S.S x)  S.` S.S x })  e₂ ⟧ᵉ 
 C.`wrap Δ e ⟧ᵉ = `λλ◯ Δ  e ⟧ᵉ 
 C.`letwrap Δ e₁ e₂ ⟧ᵉ = S.`let  e₁ ⟧ᵉ `in subst  ΔA  (S.Term _ (_ S., ΔA) _)) (inject₁-⇛₀ Δ)  e₂ ⟧ᵉ