-- Based on:
-- A Type and Scope Safe Universe of Syntaxes with Binding: Their Semantics and Proofs
-- (https://github.com/gallais/generic-syntax)
module Data.Relation where

open import Data.Sum
open import Data.List.Base hiding (lookup ; [_])

open import Data.Var hiding (_<$>_)
open import Data.Environment
open import Generic.Syntax
open import Relation.Unary hiding (U)
open import Agda.Builtin.Equality
open import Function

private
  variable
    I : Set
    σ : I
    T U : I ─Scoped
    𝓥ᴬ 𝓥ᴮ : I ─Scoped
    Γ Δ : List I


record Rel (T U : I ─Scoped) : Set₁ where
  constructor mkRel
  field rel : ∀ σ → ∀[ T σ ⇒ U σ ⇒ const Set ]

open Rel public


record All  (𝓥ᴿ : Rel 𝓥ᴬ 𝓥ᴮ) (Γ : List I)
            (ρᴬ : (Γ ─Env) 𝓥ᴬ Δ) (ρᴮ : (Γ ─Env) 𝓥ᴮ Δ) : Set where
  constructor packᴿ
  field lookupᴿ : ∀ k → rel 𝓥ᴿ σ (lookup ρᴬ k) (lookup ρᴮ k)

open All public


module _ {T U : I ─Scoped} {𝓡 : Rel T U} where
  private
    variable
      ρᵀ σᵀ : (Γ ─Env) T Δ
      ρᵁ σᵁ : (Γ ─Env) U Δ
      vᵀ : T σ Γ
      vᵁ : U σ Γ
      fᵀ : ∀ {i} → T i Γ → T i Δ
      fᵁ : ∀ {i} → U i Γ → U i Δ

  εᴿ : All 𝓡 [] ρᵀ ρᵁ
  lookupᴿ εᴿ ()

  infixl 20 _∙ᴿ_ _∷ᴿ_
  _∙ᴿ_ :  All 𝓡 Γ ρᵀ ρᵁ → rel 𝓡 σ vᵀ vᵁ → All 𝓡 (σ ∷ Γ) (ρᵀ ∙ vᵀ) (ρᵁ ∙ vᵁ)
  lookupᴿ (ρ ∙ᴿ v) z      = v
  lookupᴿ (ρ ∙ᴿ v) (s k)  = lookupᴿ ρ k

  _∷ᴿ_ :  rel 𝓡 σ (lookup ρᵀ z) (lookup ρᵁ z) →
          (∀ {σ} (v : Var σ Γ) → rel 𝓡 _ (lookup ρᵀ (s v)) (lookup ρᵁ (s v))) →
          All 𝓡 (σ ∷ Γ) ρᵀ ρᵁ
  lookupᴿ (v ∷ᴿ ρ) z      = v
  lookupᴿ (v ∷ᴿ ρ) (s k)  = ρ k

  _>>ᴿ_ :  All 𝓡 Γ ρᵀ ρᵁ → All 𝓡 Δ σᵀ σᵁ →
           All 𝓡 (Γ ++ Δ) (ρᵀ >> σᵀ) (ρᵁ >> σᵁ)
  lookupᴿ (_>>ᴿ_ {Γ} ρᴿ σᴿ) k with split Γ k
  ... | inj₁ k₁ = lookupᴿ ρᴿ k₁
  ... | inj₂ k₂ = lookupᴿ σᴿ k₂

  selectᴿ : ∀ ρ → All 𝓡 Δ ρᵀ ρᵁ → All 𝓡 Γ (select ρ ρᵀ) (select ρ ρᵁ)
  lookupᴿ (selectᴿ ρ ρᴿ) k = lookupᴿ ρᴿ (lookup ρ k)

  _<$>ᴿ_ : (∀ {i t u} → rel 𝓡 i t u → rel 𝓡 i (fᵀ t) (fᵁ u)) →
           All 𝓡 Γ ρᵀ ρᵁ → All 𝓡 Γ (fᵀ <$> ρᵀ) (fᵁ <$> ρᵁ)
  lookupᴿ (F <$>ᴿ ρ) k = F (lookupᴿ ρ k)

module _ {T : I ─Scoped} where
  private
    variable
      ρ : (Γ ─Env) T Δ

  Eqᴿ : Rel T T
  rel Eqᴿ i = _≡_

  reflᴿ : All Eqᴿ Γ ρ ρ
  lookupᴿ reflᴿ k = refl

module _ {A B : I ─Scoped} where
  open import Relation.Binary.HeterogeneousEquality.Core

  HEqᴿ : Rel A B
  rel HEqᴿ i = λ a b → a ≅ b

module _ {d : Desc I} where
  open import Generic.DeBruijn.Syntax

  VarTmᴿ : Rel Var (Tm d)
  rel VarTmᴿ i v t = `var v ≡ t
