------------------------------------------------------------------------
-- A variant of Definition.Typed.Inversion with fewer dependencies
------------------------------------------------------------------------

{-# OPTIONS --backtracking-instance-search #-}

open import Definition.Typed.Restrictions
open import Graded.Modality

module Definition.Typed.Inversion.Primitive
  {} {M : Set }
  {𝕄 : Modality M}
  (R : Type-restrictions 𝕄)
  where

open Type-restrictions R

open import Definition.Typed R
open import Definition.Typed.Properties.Admissible.Level.Primitive R
open import Definition.Typed.Properties.Admissible.U.Primitive R
open import Definition.Typed.Properties.Well-formed R
open import Definition.Typed.Size R

open import Definition.Untyped M
open import Definition.Untyped.Sup R

open import Tools.Empty
open import Tools.Fin
open import Tools.Function
open import Tools.Nat
import Tools.PropositionalEquality as PE
open import Tools.Product
import Tools.PropositionalEquality as PE
open import Tools.Relation
open import Tools.Size
open import Tools.Size.Instances
open import Tools.Sum

private variable
  α                 : Nat
  Γ                 : Cons _ _
  A B C t u l l₁ l₂ : Term _
  b                 : BinderMode
  s                 : Strength
  p q               : M
  sz                : Size

------------------------------------------------------------------------
-- Inversion for Level

opaque

  -- An inversion lemma for _⊢_∷Level.

  inversion-∷Level :
    Γ  l ∷Level 
    (Level-allowed  Γ  l  Level) ×
    (¬ Level-allowed   Γ × Level-literal l)
  inversion-∷Level (term ok ⊢l) =
      _  ⊢l) , ⊥-elim ∘→ (_$ ok)
  inversion-∷Level (literal not-ok ⊢Γ l-lit) =
    ⊥-elim ∘→ not-ok ,  _  ⊢Γ , l-lit)

opaque

  -- Inversion for Level.

  inversion-Level : Γ  Level  A  Γ  A  U zeroᵘ × Level-is-small
  inversion-Level (Levelⱼ ⊢Γ ok)    = refl (⊢U₀ ⊢Γ) , ok
  inversion-Level (conv ⊢Level eq) =
    let a , ok = inversion-Level ⊢Level
    in trans (sym eq) a , ok

opaque

  -- Inversion for Level.

  inversion-Level-⊢ : Γ  Level  Level-allowed
  inversion-Level-⊢ (Levelⱼ ok _) =
    Level-allowed⇔⊎ .proj₂ (inj₂ ok)
  inversion-Level-⊢ (univ ⊢Level) =
    let _ , ok = inversion-Level ⊢Level in
    Level-allowed⇔⊎ .proj₂ (inj₁ ok)

opaque

  -- Inversion for zeroᵘ.

  inversion-zeroᵘ : Γ  zeroᵘ  A  Γ  A  Level
  inversion-zeroᵘ (zeroᵘⱼ ok ⊢Γ)   = refl (Levelⱼ′ ok ⊢Γ)
  inversion-zeroᵘ (conv ⊢zeroᵘ eq) = trans (sym eq) (inversion-zeroᵘ ⊢zeroᵘ)

opaque

  -- Inversion for zeroᵘ.

  inversion-zeroᵘ-⊢ : Γ  zeroᵘ   λ l  Γ  U l  Level
  inversion-zeroᵘ-⊢ (univ ⊢zeroᵘ) = _ , inversion-zeroᵘ ⊢zeroᵘ

------------------------------------------------------------------------
-- Inversion for U

opaque

  -- Inversion for U.

  inversion-U : Γ  U t  A  Γ  A  U (sucᵘ t)
  inversion-U (Uⱼ ⊢t)        = refl (⊢U (⊢sucᵘ ⊢t))
  inversion-U (conv ⊢U B≡A) = trans (sym B≡A) (inversion-U ⊢U)

  inversion-U∷-Level : Γ  U l  A  Γ  l ∷Level
  inversion-U∷-Level (Uⱼ ⊢l)     = ⊢l
  inversion-U∷-Level (conv ⊢U _) = inversion-U∷-Level ⊢U

  inversion-U-Level : Γ  U l  Γ  l ∷Level
  inversion-U-Level (univ ⊢U) = inversion-U∷-Level ⊢U

------------------------------------------------------------------------
-- Inversion for Lift

opaque

  inversion-Lift∷ :
    Γ  Lift t A  B 
     λ k₁  Γ  t ∷Level × Γ  A  U k₁ × Γ  B  U (k₁ supᵘₗ t)
  inversion-Lift∷ (conv x x₁) =
    let _ , ⊢t , ⊢A , B≡ = inversion-Lift∷ x
    in _ , ⊢t , ⊢A , trans (sym x₁) B≡
  inversion-Lift∷ (Liftⱼ ⊢l₁ ⊢l₂ ⊢A) =
    _ , ⊢l₂ , ⊢A , refl (⊢U (⊢supᵘₗ ⊢l₁ ⊢l₂))

  inversion-Lift : Γ  Lift t A  Γ  t ∷Level × Γ  A
  inversion-Lift (univ x) =
    let _ , ⊢t , ⊢A , B≡ = inversion-Lift∷ x
    in ⊢t , univ ⊢A
  inversion-Lift (Liftⱼ x x₁) = x , x₁

  inversion-lift : Γ  lift t  A  ∃₂ λ l B  Γ  t  B × Γ  A  Lift l B
  inversion-lift (conv a x) =
    let _ , _ , ⊢t , A≡Lift = inversion-lift a
    in _ , _ , ⊢t , trans (sym x) A≡Lift
  inversion-lift (liftⱼ a₁ a₂ a₃) = _ , _ , a₃ , refl (Liftⱼ a₁ a₂)

------------------------------------------------------------------------
-- Inversion for Empty

opaque

  -- Inversion for Empty.

  inversion-Empty : Γ  Empty  A  Γ  A  U zeroᵘ
  inversion-Empty (Emptyⱼ ⊢Γ)      = refl (⊢U₀ ⊢Γ)
  inversion-Empty (conv ⊢Empty eq) =
    trans (sym eq) (inversion-Empty ⊢Empty)

opaque

  -- Inversion for emptyrec.

  inversion-emptyrec :
    Γ  emptyrec p A t  B 
    (Γ  A) × Γ  t  Empty × Γ  B  A
  inversion-emptyrec (emptyrecⱼ ⊢A ⊢t) =
    ⊢A , ⊢t , refl ⊢A
  inversion-emptyrec (conv ⊢er eq) =
    let a , b , c = inversion-emptyrec ⊢er
    in  a , b , trans (sym eq) c

------------------------------------------------------------------------
-- Inversion for Unit

opaque

  -- Inversion for Unit.

  inversion-Unit-U : Γ  Unit s  A  Γ  A  U zeroᵘ × Unit-allowed s
  inversion-Unit-U (Unitⱼ ⊢Γ ok)    = refl (⊢U₀ ⊢Γ) , ok
  inversion-Unit-U (conv ⊢Unit B≡A) =
    let B≡U , ok = inversion-Unit-U ⊢Unit in
    trans (sym B≡A) B≡U , ok

opaque

  -- Inversion for Unit.

  inversion-Unit : Γ  Unit s  Unit-allowed s
  inversion-Unit = λ where
    (univ ⊢Unit) 
      let _ , ok = inversion-Unit-U ⊢Unit in
      ok

opaque

  -- Inversion for star.

  inversion-star :
    Γ  star s  A  Γ  A  Unit s × Unit-allowed s
  inversion-star (starⱼ ⊢Γ ok)   = refl (univ (Unitⱼ ⊢Γ ok)) , ok
  inversion-star (conv ⊢star eq) =
    let a , b = inversion-star ⊢star in
    trans (sym eq) a , b

------------------------------------------------------------------------
-- Inversion for ℕ

opaque

  -- Inversion for ℕ.

  inversion-ℕ : Γ    A  Γ  A  U zeroᵘ
  inversion-ℕ (ℕⱼ ⊢Γ)      = refl (⊢U₀ ⊢Γ)
  inversion-ℕ (conv ⊢ℕ eq) = trans (sym eq) (inversion-ℕ ⊢ℕ)

opaque

  -- Inversion for zero.

  inversion-zero : Γ  zero  A  Γ  A  
  inversion-zero (zeroⱼ ⊢Γ)      = refl (univ (ℕⱼ ⊢Γ))
  inversion-zero (conv ⊢zero eq) = trans (sym eq) (inversion-zero ⊢zero)

opaque

  -- Inversion for suc.

  inversion-suc : Γ  suc t  A  Γ  t   × Γ  A  
  inversion-suc (sucⱼ ⊢t)      = ⊢t , refl (univ (ℕⱼ (wfTerm ⊢t)))
  inversion-suc (conv ⊢suc eq) =
    let a , b = inversion-suc ⊢suc in
    a , trans (sym eq) b

------------------------------------------------------------------------
-- Inversion for Id

opaque
  unfolding size-⊢∷

  -- An inversion lemma for Id.

  inversion-Id-⊢∷ :
    (⊢Id : Γ  Id A t u  B) 
    ( λ (⊢A : Γ  A  B)  size-⊢∷ ⊢A  size-⊢∷ ⊢Id) ×
    ( λ (⊢t : Γ  t  A)  size-⊢∷ ⊢t  size-⊢∷ ⊢Id) ×
    ( λ (⊢u : Γ  u  A)  size-⊢∷ ⊢u  size-⊢∷ ⊢Id)
  inversion-Id-⊢∷ (Idⱼ ⊢A ⊢t ⊢u) = (⊢A , !) , (⊢t , !) , (⊢u , !)
  inversion-Id-⊢∷ (conv ⊢Id ≡U)  =
    let (⊢A , A<) , (⊢t , t<) , (⊢u , u<) = inversion-Id-⊢∷ ⊢Id in
    (conv ⊢A ≡U , A< ↙⊕ ) , (⊢t ,  <ˢ→≤ˢ t<) , (⊢u ,  <ˢ→≤ˢ u<)

opaque
  unfolding size-⊢

  -- An inversion lemma for Id.

  inversion-Id-⊢ :
    (⊢Id : Γ  Id A t u) 
    ( λ (⊢A : Γ  A)  size-⊢ ⊢A  size-⊢ ⊢Id) ×
    ( λ (⊢t : Γ  t  A)  size-⊢∷ ⊢t  size-⊢ ⊢Id) ×
    ( λ (⊢u : Γ  u  A)  size-⊢∷ ⊢u  size-⊢ ⊢Id)
  inversion-Id-⊢ (Idⱼ ⊢A ⊢t ⊢u) = (⊢A , !) , (⊢t , !) , (⊢u , !)
  inversion-Id-⊢ (univ ⊢Id)     =
    let (⊢A , A<) , (⊢t , t<) , (⊢u , u<) = inversion-Id-⊢∷ ⊢Id in
    (univ ⊢A , A< ↙⊕ ) , (⊢t ,  <ˢ→≤ˢ t<) , (⊢u ,  <ˢ→≤ˢ u<)

opaque
  unfolding size-⊢

  -- A variant of inversion-Id-⊢.

  inversion-Id-⊢-<ˢ :
    ( λ (⊢Id : Γ  Id A t u)  size-⊢ ⊢Id  sz) 
    ( λ (⊢A : Γ  A)  size-⊢ ⊢A  sz) ×
    ( λ (⊢t : Γ  t  A)  size-⊢∷ ⊢t  sz) ×
    ( λ (⊢u : Γ  u  A)  size-⊢∷ ⊢u  sz)
  inversion-Id-⊢-<ˢ (⊢Id , lt) =
    let (⊢A , A<) , (⊢t , t<) , (⊢u , u<) = inversion-Id-⊢ ⊢Id in
    (⊢A , <ˢ-trans A< lt) , (⊢t , <ˢ-trans t< lt) ,
    (⊢u , <ˢ-trans u< lt)

opaque

  -- Inversion for Id.

  inversion-Id :
    Γ  Id A t u 
    (Γ  A) × Γ  t  A × Γ  u  A
  inversion-Id ⊢Id =
    let (⊢A , _) , (⊢t , _) , (⊢u , _) = inversion-Id-⊢ ⊢Id in
    ⊢A , ⊢t , ⊢u

------------------------------------------------------------------------
-- Inversion for Π and Σ

opaque
  unfolding size-⊢∷

  -- An inversion lemma for ΠΣ⟨_⟩_,_▷_▹_.

  inversion-ΠΣ-⊢∷ :
    (⊢ΠΣ : Γ  ΠΣ⟨ b  p , q  A  B  C) 
     λ l 
    Γ  l ∷Level ×
    ( λ (⊢A : Γ  A  U l)  size-⊢∷ ⊢A  size-⊢∷ ⊢ΠΣ) ×
    ( λ (⊢B : Γ »∙ A  B  U (wk1 l))  size-⊢∷ ⊢B  size-⊢∷ ⊢ΠΣ) ×
    Γ  C  U l ×
    ΠΣ-allowed b p q
  inversion-ΠΣ-⊢∷ (ΠΣⱼ ⊢l ⊢A ⊢B ok) =
    _ , ⊢l , (⊢A , !) , (⊢B , !) , refl (⊢U ⊢l) , ok
  inversion-ΠΣ-⊢∷ (conv ⊢ΠΣ eq₁) =
    let _ , ⊢l , (⊢A , A<) , (⊢B , B<) , eq₂ , ok =
          inversion-ΠΣ-⊢∷ ⊢ΠΣ
    in
    _ , ⊢l , (⊢A ,  <ˢ→≤ˢ A<) , (⊢B ,  <ˢ→≤ˢ B<) ,
    trans (sym eq₁) eq₂ , ok

opaque

  -- Inversion for ΠΣ⟨_⟩_,_▷_▹_.

  inversion-ΠΣ-U :
    Γ  ΠΣ⟨ b  p , q  A  B  C 
     λ l 
      Γ  l ∷Level ×
      Γ  A  U l × Γ »∙ A  B  U (wk1 l) × Γ  C  U l ×
      ΠΣ-allowed b p q
  inversion-ΠΣ-U ⊢ΠΣ =
    let _ , ⊢l , (⊢A , _) , (⊢B , _) , C≡ , ok = inversion-ΠΣ-⊢∷ ⊢ΠΣ in
    _ , ⊢l , ⊢A , ⊢B , C≡ , ok

opaque
  unfolding size-⊢

  -- An inversion lemma for ΠΣ⟨_⟩_,_▷_▹_.

  inversion-ΠΣ-⊢ :
    (⊢ΠΣ : Γ  ΠΣ⟨ b  p , q  A  B) 
    ( λ (⊢A : Γ  A)  size-⊢ ⊢A  size-⊢ ⊢ΠΣ) ×
    ( λ (⊢B : Γ »∙ A  B)  size-⊢ ⊢B  size-⊢ ⊢ΠΣ) ×
    ΠΣ-allowed b p q
  inversion-ΠΣ-⊢ (ΠΣⱼ ⊢B ok) =
    let _ , (⊢A , A<) = ∙⊢→⊢-<ˢ ⊢B in
    (⊢A , <ˢ-trans A< !) , (⊢B ,  ) , ok
  inversion-ΠΣ-⊢ (univ ⊢ΠΣ) =
    let _ , _ , (⊢A , A<) , (⊢B , B<) , _ , ok = inversion-ΠΣ-⊢∷ ⊢ΠΣ in
    (univ ⊢A , A< ↙⊕ ) , (univ ⊢B , B< ↙⊕ ) , ok

opaque
  unfolding size-⊢

  -- A variant of inversion-ΠΣ-⊢.

  inversion-ΠΣ-⊢-<ˢ :
    ( λ (⊢ΠΣ : Γ  ΠΣ⟨ b  p , q  A  B)  size-⊢ ⊢ΠΣ  sz) 
    ( λ (⊢A : Γ  A)  size-⊢ ⊢A  sz) ×
    ( λ (⊢B : Γ »∙ A  B)  size-⊢ ⊢B  sz) ×
    ΠΣ-allowed b p q
  inversion-ΠΣ-⊢-<ˢ (⊢ΠΣ , lt) =
    let (⊢A , A<) , (⊢B , B<) , ok = inversion-ΠΣ-⊢ ⊢ΠΣ in
    (⊢A , <ˢ-trans A< lt) , (⊢B , <ˢ-trans B< lt) , ok

opaque

  -- Inversion for ΠΣ⟨_⟩_,_▷_▹_.

  inversion-ΠΣ :
    Γ  ΠΣ⟨ b  p , q  A  B 
    Γ  A × Γ »∙ A  B × ΠΣ-allowed b p q
  inversion-ΠΣ ⊢ΠΣ =
    let (⊢A , _) , (⊢B , _) , ok = inversion-ΠΣ-⊢ ⊢ΠΣ in
    ⊢A , ⊢B , ok

opaque

  -- Inversion for prod.

  inversion-prod :
    Γ  prod s p t u  A 
    ∃₃ λ B C q 
      (Γ  B) × (Γ »∙ B  C) ×
      Γ  t  B × Γ  u  C [ t ]₀ ×
      Γ  A  Σ⟨ s  p , q  B  C ×
      Σ-allowed s p q
  inversion-prod (prodⱼ ⊢C ⊢t ⊢u ok) =
    _ , _ , _ , ⊢∙→⊢ (wf ⊢C) , ⊢C , ⊢t , ⊢u , refl (ΠΣⱼ ⊢C ok) , ok
  inversion-prod (conv ⊢prod eq) =
    let a , b , c , d , e , f , g , h , i = inversion-prod ⊢prod in
    a , b , c , d , e , f , g , trans (sym eq) h , i

opaque

  -- Inversion for fst.

  inversion-fst :
    Γ  fst p t  A 
    ∃₃ λ B C q 
      (Γ  B) × (Γ »∙ B  C) ×
      Γ  t  Σˢ p , q  B  C ×
      Γ  A  B
  inversion-fst (fstⱼ ⊢C ⊢t) =
    let ⊢B = ⊢∙→⊢ (wf ⊢C) in
    _ , _ , _ , ⊢B , ⊢C , ⊢t , refl ⊢B
  inversion-fst (conv ⊢fst eq) =
    let a , b , c , d , e , f , g = inversion-fst ⊢fst in
    a , b , c , d , e , f , trans (sym eq) g