module Generic.Identity where

open import Size
open import Agda.Builtin.List
open import Data.Product hiding (zip)
open import Data.Sum
open import var
open import rel
open import varlike
open import environment
open import Generic.Syntax
open import Generic.Semantics
open import Generic.Zip
open import Generic.Simulation

open import Function
open import Relation.Binary.PropositionalEquality as PEq
open ≡-Reasoning

module _ {I : Set} {d : Desc I} where

 data _≅_ {σ : I} {Γ : List I} : {s : Size}  Tm d s σ Γ  {t : Size}  Tm d t σ Γ  Set
 ⟨_⟩_≅_ : (e : Desc I) {σ : I} {Γ : List I} {s : Size}   e  (Scope (Tm d s)) σ Γ  {t : Size}   e  (Scope (Tm d t)) σ Γ  Set

 data _≅_ {σ} {Γ} where
   `var : {s t : Size} {k l : Var σ Γ}  k  l  `var {s = s} k  `var {s = t} l
   `con : {s t : Size} {b :  d  (Scope (Tm d s)) σ Γ} {c :  d  (Scope (Tm d t)) σ Γ} 
           d  b  c  `con {s = s} b  `con {s = t} c

  e  b  c = Zip e  _ _  t u  t  u) b c

 ≅⇒≡   :  {σ Γ} {t u : Tm d  σ Γ}  t  u  t  u
 ⟨_⟩≅⇒≡ :  {σ Γ} e {t u :  e  (Scope (Tm d )) σ Γ}   e  t  u  t  u

 ≅⇒≡ (`var eq) = cong `var eq
 ≅⇒≡ (`con eq) = cong `con ( d ⟩≅⇒≡ eq)

   A d   ⟩≅⇒≡ (refl , eq) = cong ,_ ( d _ ⟩≅⇒≡ eq)
  `X Δ j d ⟩≅⇒≡ (≅-pr , eq) = cong₂ _,_ (≅⇒≡ ≅-pr) ( d ⟩≅⇒≡ eq)
  `∎ i     ⟩≅⇒≡ eq          = proof-irrelevance _ _

module RenId {I : Set} {d : Desc I} where

 ren-id      :  {s : Size} {i Γ} (t : Tm d s i Γ) {ρ : Thinning Γ Γ}  ∀[ Eq^R ] ρ (base vl^Var)  ren ρ t  t
 ren-body-id :  Δ i {Γ s} (t : Scope (Tm d s) Δ i Γ) {ρ : Thinning Γ Γ}  ∀[ Eq^R ] ρ (base vl^Var)  reify vl^Var Δ i (Sem.body Renaming ρ Δ i t)  t

 ren-id (`var k) ρ^R = `var (trans (lookup^R ρ^R k) (lookup-base^Var k))
 ren-id (`con t) ρ^R = `con (subst₂ ( d ⟩_≅_) (sym $ fmap² d (Sem.body Renaming _) (reify vl^Var) _) (fmap-id d _)
                            $ zip d  Δ i t  ren-body-id Δ i t ρ^R) _)

 ren-body-id []        i t     = ren-id t
 ren-body-id Δ@(_  _) i {Γ} t {ρ} ρ^R = ren-id t eq^R where

  eq^R : ∀[ Eq^R ] (lift vl^Var Δ ρ) (base vl^Var)
  lookup^R eq^R k with split Δ k | inspect (split Δ) k
  ... | inj₁ k₁ | PEq.[ eq ] = begin
    injectˡ Γ (lookup (base vl^Var) k₁) ≡⟨ cong (injectˡ Γ) (lookup-base^Var k₁) 
    injectˡ Γ k₁                        ≡⟨ injectˡ-split Δ k eq 
    k                                   ≡⟨ sym (lookup-base^Var k) 
    lookup (base vl^Var) k              
  ... | inj₂ k₂ | PEq.[ eq ] = begin
    injectʳ Δ (lookup (base vl^Var) (lookup ρ k₂)) ≡⟨ cong (injectʳ Δ) (lookup-base^Var _) 
    injectʳ Δ (lookup ρ k₂)                        ≡⟨ cong (injectʳ Δ) (lookup^R ρ^R k₂) 
    injectʳ Δ (lookup (base vl^Var) k₂)            ≡⟨ cong (injectʳ Δ) (lookup-base^Var k₂) 
    injectʳ Δ k₂                                   ≡⟨ injectʳ-split Δ k eq 
    k                                              ≡⟨ sym (lookup-base^Var k) 
    lookup (base vl^Var) k                         

module _ {I : Set} {d : Desc I} where

  ren-id :  {σ Γ} (t : Tm d  σ Γ)  ren (base vl^Var) t  t
  ren-id t = ≅⇒≡ (RenId.ren-id t (pack^R λ _  refl))

  sub-id :  {σ Γ} (t : Tm d  σ Γ)  sub (base vl^Tm) t  t
  sub-id t = begin
    sub (base vl^Tm) t  ≡⟨ sym $ Sim.sim RenSub base^VarTm^R t 
    ren (base vl^Var) t ≡⟨ ren-id t 
    t