import Syntax.Simple.Signature  as S
import Syntax.BiTyped.Signature as B

import Theory.ModeCorrectness.Signature as MC

module Theory.ModeCorrectness.Properties {SD : S.SigD}
  (D : B.SigD SD) (mc : MC.ModeCorrect SD D) where

open import Prelude

import Data.List.Relation.Unary.All as All

open import Syntax.Simple  SD
open import Syntax.Context SD

import      Syntax.Typed.Raw.Functor       SD as R
open import Syntax.BiTyped.Functor         SD
import      Theory.ModeCorrectness.Functor SD as M

open import Theory.Erasure

open import Syntax.Typed.Raw.Term (erase D)
open import Syntax.BiTyped.Term          D

open import Theory.ModeCorrectness.UniqueSynthesised D mc

open MC SD
open B  SD
open ≡-Reasoning

private variable
  d     : Mode
  Ξ n   : 
  xs ys : Fins# Ξ
  Γ     : Cxt 0
  t u   : Raw n

module _ {ρ σ : ∃Sub⊆ Ξ} (ρ≤σ : ρ  σ) where
  ρ≤σ→⊢tᵃ
    : (Δ : TExps Ξ) {Δ⊆xs : Cover _ Δ} {Δ⊆xs′ : Cover _ Δ}
     {Γ : Cxt 0} {t : R.⟦ Δ ⟧ᵃ Raw (length Γ)} {B : Ty}
     M.⟦ Δ ⟧ᵃ σ Δ⊆xs  Raw (_⊢_[ d ] B) Γ t
     M.⟦ Δ ⟧ᵃ ρ Δ⊆xs′ Raw (_⊢_[ d ] B) Γ t
  ρ≤σ→⊢tᵃ []                ⊢t = ⊢t
  ρ≤σ→⊢tᵃ (A  Δ) {A⊆  Δ⊆} {A⊆′  Δ⊆′} ⊢t
    rewrite sub⊆-cong (ρ .proj₂) (σ .proj₂) A A⊆′ A⊆  x∈  begin
        ρ .proj₂ _
          ≡⟨ ρ≤σ .consistency _  
        σ .proj₂ _
          ≡⟨ cong (σ .proj₂) (#∈-uniq _ _) 
        σ .proj₂ _
          ) = ρ≤σ→⊢tᵃ Δ ⊢t

module _ {ρ σ : ∃Sub⊆ Ξ} (ρ≤σ : ρ  σ) where
  ρ≤σ→⊢tᵃ′
    : (Δ : TExps Ξ) {Δ⊆xs : Cover _ Δ} {Δ⊆xs′ : Cover _ Δ}
     {Γ : Cxt 0} {t : R.⟦ Δ ⟧ᵃ Raw (length Γ)} {B : Ty}
     M.⟦ Δ ⟧ᵃ ρ Δ⊆xs′ Raw (_⊢_[ d ] B) Γ t
     M.⟦ Δ ⟧ᵃ σ Δ⊆xs  Raw (_⊢_[ d ] B) Γ t
  ρ≤σ→⊢tᵃ′ []      ⊢t = ⊢t
  ρ≤σ→⊢tᵃ′ (A  Δ) {A⊆xs  ⊆xs} {A⊆xs′  ⊆xs′} ⊢t
    rewrite sub⊆-cong (ρ .proj₂) (σ .proj₂) A A⊆xs′ A⊆xs λ x∈ 
      begin
        ρ .proj₂ (A⊆xs′ x∈)
          ≡⟨ ρ≤σ .consistency (A⊆xs′ x∈)  
        σ .proj₂ _
          ≡⟨ cong (σ .proj₂) (#∈-uniq _ _) 
        σ .proj₂ (A⊆xs x∈)
           = ρ≤σ→⊢tᵃ′ Δ ⊢t

  ρ≤σ→⊢tⁿ′
    : (Ds : ArgsD Ξ) (ys : Fins# Ξ) (mc : ModeCorrectᵃˢ ys Ds)
     {Ds⊆  : ys  known Ds #⊆ _}
     {Ds⊆′ : ys  known Ds #⊆ _}
     {Γ : Cxt 0} {ts : R.⟦ eraseᵃˢ Ds ⟧ᵃˢ Raw (length Γ)}
     M.⟦ Ds ⟧ᵃˢ ρ ys Ds⊆  mc Raw _⊢_[_]_ Γ ts
     M.⟦ Ds ⟧ᵃˢ σ ys Ds⊆′ mc Raw _⊢_[_]_ Γ ts
  ρ≤σ→⊢tⁿ′ []                   _  _     _   = tt
  ρ≤σ→⊢tⁿ′ (Δ ⊢[ Chk ] Aₙ  Ds) ys (A⊆  Δ⊆ , mc) {Ds⊆} {Ds⊆′} (⊢t , ⊢ts)
    rewrite sub⊆-cong (ρ .proj₂) (σ .proj₂) Aₙ (Ds⊆  A⊆) (Ds⊆′  A⊆) λ x∈ 
      begin
        ρ .proj₂ _
          ≡⟨ ρ≤σ .consistency _  
        σ .proj₂ _
          ≡⟨ cong (σ .proj₂) (#∈-uniq _ _) 
        σ .proj₂ _
           = ρ≤σ→⊢tᵃ′ Δ ⊢t , ρ≤σ→⊢tⁿ′ _ _ _ ⊢ts
  ρ≤σ→⊢tⁿ′ (Δ ⊢[ Syn ] Aₙ  Ds) ys (Δ⊆ , mc) {Ds⊆} {Ds⊂′} (⊢t , ⊢ts)
    rewrite sub⊆-cong (ρ .proj₂) (σ .proj₂) Aₙ  x  Ds⊆ (∪⁺ʳ ys (∪⁺ˡ x)))  x  Ds⊂′ (∪⁺ʳ ys (∪⁺ˡ x))) λ x∈ 

      begin
        ρ .proj₂ _
          ≡⟨ ρ≤σ .consistency _  
        σ .proj₂ _
          ≡⟨ cong (σ .proj₂) (#∈-uniq _ _) 
        σ .proj₂ _
           = ρ≤σ→⊢tᵃ′ Δ ⊢t , ρ≤σ→⊢tⁿ′ _ _ _ ⊢ts

------------------------------------------------------------------------
-- Typing derivations with substitution
-- to derivatios with partial substitution

module _ {σ : TSub Ξ 0} where
  ⊢ᵃ→Sub⊆⊢ᵃ
    :  Δ {Γ} A {t}
     {Δ⊆ : Cover (enumerate Ξ) Δ}
      Δ ⟧ᵃ Raw (_⊢_[ d ] (A  σ )) σ Γ t
     M.⟦ Δ ⟧ᵃ (_ , Sub⇒Sub⊆ σ) Δ⊆ Raw (_⊢_[ d ] (sub⊆ (Sub⇒Sub⊆ σ) A λ {x} _  ⊆enum x)) Γ t
  ⊢ᵃ→Sub⊆⊢ᵃ []      {Γ} B ⊢t rewrite sub⊆=sub σ B = ⊢t
  ⊢ᵃ→Sub⊆⊢ᵃ (A  Δ) {Γ} B {t} {A⊆  Δ⊆} ⊢t
    rewrite sub⊆=sub σ A rewrite sub⊆-⊆-irrelevant (Sub⇒Sub⊆ σ) A   {x = x₁} _  ⊆enum x₁) A⊆ =
    ⊢ᵃ→Sub⊆⊢ᵃ Δ B ⊢t

  ⊢ᵃˢ→Sub⊆⊢ᵃˢ
    : {Ds : ArgsD Ξ}
     {mc : ModeCorrectᵃˢ ys Ds}
     {Γ : Cxt 0} {ts : R.⟦ eraseᵃˢ Ds ⟧ᵃˢ Raw (length Γ)}
      Ds ⟧ᵃˢ Raw _⊢_[_]_ σ Γ ts
     M.⟦ Ds ⟧ᵃˢ (_ , Sub⇒Sub⊆ σ) ys  {x} _  ⊆enum x) mc Raw _⊢_[_]_ Γ ts
  ⊢ᵃˢ→Sub⊆⊢ᵃˢ {Ds = []}                                  _          = tt
  ⊢ᵃˢ→Sub⊆⊢ᵃˢ {Ds = Δ B.⊢[ Chk ] Aₙ  Ds} {A⊆  Δ⊆ , mc} {ts = t , ts} (⊢t , ⊢ts) =
     ⊢ᵃ→Sub⊆⊢ᵃ Δ Aₙ ⊢t  , ⊢ᵃˢ→Sub⊆⊢ᵃˢ ⊢ts
  ⊢ᵃˢ→Sub⊆⊢ᵃˢ {Ds = Δ ⊢[ Syn ] Aₙ  Ds}   {Δ⊆ , mc}      (⊢t , ⊢ts) =
    ⊢ᵃ→Sub⊆⊢ᵃ Δ Aₙ ⊢t , ⊢ᵃˢ→Sub⊆⊢ᵃˢ ⊢ts

-----------------------------------------------------------------------
-- Typing derivations with partial substitution
-- to derivatios with substitution

module _ {ρ : Sub⊆ Ξ xs} where
  Sub⊆⊢ᵃ→⊢ᵃ
    :  Δ {Γ} A {t}
     (Δ⊆ : Cover xs Δ)
     (A⊆ : vars A #⊆ xs)
     (⊆xs :  x  x #∈ xs)
     M.⟦ Δ ⟧ᵃ (_ , ρ) Δ⊆ Raw (_⊢_[ d ] (sub⊆ ρ A A⊆)) Γ t
      Δ ⟧ᵃ Raw (_⊢_[ d ] (sub (ρ  ⊆xs) A)) (ρ  ⊆xs) Γ t
  Sub⊆⊢ᵃ→⊢ᵃ []      B _         B⊆ ⊆xs ⊢t rewrite sub⊆=sub′ ρ ⊆xs B B⊆ = ⊢t
  Sub⊆⊢ᵃ→⊢ᵃ (A  Δ) B (A⊆  Δ⊆) B⊆ ⊆xs ⊢t rewrite sub⊆=sub′ ρ ⊆xs A A⊆ =
    Sub⊆⊢ᵃ→⊢ᵃ Δ B Δ⊆ B⊆ ⊆xs ⊢t

  Sub⊆⊢ᵃˢ→⊢ᵃˢ
    : {Ds : ArgsD Ξ} {ys : Fins# Ξ}
     {⊆xs : (x : Fin Ξ)  x #∈ xs} {ys∪Ds⊆ : ys  known Ds #⊆ xs} {mc : ModeCorrectᵃˢ ys Ds}
     {Γ : Cxt 0} {ts : R.⟦ eraseᵃˢ Ds ⟧ᵃˢ Raw (length Γ)}
     M.⟦ Ds ⟧ᵃˢ (_ , ρ) ys ys∪Ds⊆ mc Raw _⊢_[_]_ Γ ts
      Ds ⟧ᵃˢ Raw _⊢_[_]_ (Sub⊆⇒Sub ρ ⊆xs) Γ ts
  Sub⊆⊢ᵃˢ→⊢ᵃˢ {[]}                              tt = tt
  Sub⊆⊢ᵃˢ→⊢ᵃˢ {Δ ⊢[ Chk ] Aₙ  Ds} {ys} {⊆xs} {ys∪Ds⊆} {A⊆  Ds⊆ , mc} {Γ} {t , ts} (⊢t , ⊢ts) =
     Sub⊆⊢ᵃ→⊢ᵃ Δ Aₙ _ _ _ ⊢t  , Sub⊆⊢ᵃˢ→⊢ᵃˢ ⊢ts
  Sub⊆⊢ᵃˢ→⊢ᵃˢ {Δ ⊢[ Syn ] Aₙ  Ds} {ys} {⊆xs} {ys∪Ds⊆} {mc} {Γ} {t , ts} (⊢t , ⊢ts) =
    Sub⊆⊢ᵃ→⊢ᵃ Δ Aₙ _ _ _ ⊢t , Sub⊆⊢ᵃˢ→⊢ᵃˢ ⊢ts