{-# OPTIONS --without-K --safe #-}
module DsubReduced where
open import Data.List as List
open import Data.List.All as All
open import Data.Nat as ℕ
open import Data.Maybe as Maybe
open import Data.Product
open import Function
open import Data.Maybe.Properties as Maybeₚ
open import Data.Nat.Properties as ℕₚ
open import Relation.Nullary
open import Relation.Binary.PropositionalEquality as ≡
open import DsubDef
open import FsubMinus
open import FsubMinus2
open import Utils
infix 4 _⊢ᵣ_<:_
data _⊢ᵣ_<:_ : Env → Typ → Typ → Set where
  drtop   : ∀ {Γ T} → Covar T → Γ ⊢ᵣ T <: ⊤
  drrefl  : ∀ {Γ T} → Covar T → Γ ⊢ᵣ T <: T
  drall   : ∀ {Γ S U S′ U′} →
              Covar S → Covar U → Covar S′ → Covar U′ →
              (S′<:S : Γ ⊢ᵣ S′ <: S) →
              (U<:U′ : ⟨A: ⊥ ⋯ S′ ⟩ ∷ Γ ⊢ᵣ U <: U′) →
              Γ ⊢ᵣ Π ⟨A: ⊥ ⋯ S ⟩ ∙ U <: Π ⟨A: ⊥ ⋯ S′ ⟩ ∙ U′
  drsel   : ∀ {Γ n U U′} →
              (T∈Γ : env-lookup Γ n ≡ just ⟨A: ⊥ ⋯ U ⟩) →
              Covar U →
              Γ ⊢ᵣ U <: U′ →
              Γ ⊢ᵣ n ∙A <: U′
module FsubMinusToDsubR where
  open FsubMinus.FsubMinus renaming (Env to Env′ ; _↑_ to _⇑_) hiding (env-lookup)
  infix 5 ⟦_⟧ ⟪_⟫
  ⟦_⟧ : Ftyp → Typ
  ⟦ ⊤ ⟧         = ⊤
  ⟦ var x ⟧     = x ∙A
  ⟦ Π<: S ∙ U ⟧ = Π ⟨A: ⊥ ⋯ ⟦ S ⟧ ⟩ ∙ ⟦ U ⟧
  ⟪_⟫ : Env′ → Env
  ⟪ [] ⟫    = []
  ⟪ T ∷ Γ ⟫ = ⟨A: ⊥ ⋯ ⟦ T ⟧ ⟩ ∷ ⟪ Γ ⟫
  module ⟦⟧-Bijective where
    open import Function.Bijection
    open import Function.Surjection
    open import Function.Equality
    CovTyp : Set
    CovTyp = ∃ λ T → Covar T
    ⟦⟧-covar : ∀ T → Covar ⟦ T ⟧
    ⟦⟧-covar ⊤           = cv⊤
    ⟦⟧-covar (var x)     = cv∙A _
    ⟦⟧-covar (Π<: S ∙ U) = cvΠ (⟦⟧-covar S) (⟦⟧-covar U)
    ⟦⟧-func : ≡.setoid Ftyp ⟶ ≡.setoid CovTyp
    ⟦⟧-func   = record
      { _⟨$⟩_ = < ⟦_⟧ , ⟦⟧-covar >
      ; cong  = ≡.cong < ⟦_⟧ , ⟦⟧-covar >
      }
    ⟦⟧-injective : ∀ {S U} → ⟦ S ⟧ ≡ ⟦ U ⟧ → S ≡ U
    ⟦⟧-injective {⊤} {⊤} eq            = refl
    ⟦⟧-injective {⊤} {var x} ()
    ⟦⟧-injective {⊤} {Π<: _ ∙ _} ()
    ⟦⟧-injective {var x} {⊤} ()
    ⟦⟧-injective {var x} {var .x} refl = refl
    ⟦⟧-injective {var x} {Π<: _ ∙ _} ()
    ⟦⟧-injective {Π<: _ ∙ _} {⊤} ()
    ⟦⟧-injective {Π<: _ ∙ _} {var x} ()
    ⟦⟧-injective {Π<: S₁ ∙ U₁} {Π<: S₂ ∙ U₂} eq
      with ⟦ S₁ ⟧ | ⟦ S₂ ⟧ | ⟦ U₁ ⟧ | ⟦ U₂ ⟧
         | ⟦⟧-injective {S₁} {S₂} | ⟦⟧-injective {U₁} {U₂}
    ⟦⟧-injective {Π<: S₁ ∙ U₁} {Π<: S₂ ∙ U₂} refl
         | _ | _ | _ | _ | rec₁ | rec₂ = ≡.cong₂ Π<:_∙_ (rec₁ refl) (rec₂ refl)
    ⟦⟧-func-injective : ∀ {S U} → (CovTyp ∋ (⟦ S ⟧ , ⟦⟧-covar S)) ≡ (⟦ U ⟧ , ⟦⟧-covar U) → S ≡ U
    ⟦⟧-func-injective {S} {U} eq
      with ⟦ S ⟧ | ⟦⟧-covar S | ⟦ U ⟧ | ⟦⟧-covar U
         | ⟦⟧-injective {S} {U}
    ⟦⟧-func-injective {S} {U} refl
         | _ | _ | _ | _ | inj = inj refl
    infix 5 ⟦_⟧⁻¹
    ⟦_⟧⁻¹ : CovTyp → Ftyp
    ⟦ _ , cv⊤ ⟧⁻¹     = ⊤
    ⟦ _ , cv∙A x ⟧⁻¹  = var x
    ⟦ _ , cvΠ S U ⟧⁻¹ = Π<: ⟦ -, S ⟧⁻¹ ∙ ⟦ -, U ⟧⁻¹
    ⟦⟧-func-inv : ≡.setoid CovTyp ⟶ ≡.setoid Ftyp
    ⟦⟧-func-inv = record
      { _⟨$⟩_   = ⟦_⟧⁻¹
      ; cong    = ≡.cong ⟦_⟧⁻¹
      }
    ⟦⟧-left-inverse-⟦⟧⁻¹ : ∀ {T} (cT : Covar T) → (⟦ ⟦ -, cT ⟧⁻¹ ⟧ , ⟦⟧-covar ⟦ -, cT ⟧⁻¹) ≡ (CovTyp ∋ (-, cT))
    ⟦⟧-left-inverse-⟦⟧⁻¹ cv⊤           = refl
    ⟦⟧-left-inverse-⟦⟧⁻¹ (cv∙A n)      = refl
    ⟦⟧-left-inverse-⟦⟧⁻¹ (cvΠ S U)
      with ⟦ ⟦ -, S ⟧⁻¹ ⟧         | ⟦ ⟦ -, U ⟧⁻¹ ⟧ 
         | ⟦⟧-covar ⟦ -, S ⟧⁻¹    | ⟦⟧-covar ⟦ -, U ⟧⁻¹
         | ⟦⟧-left-inverse-⟦⟧⁻¹ S | ⟦⟧-left-inverse-⟦⟧⁻¹ U
    ...  | _ | _ | _ | _ | refl | refl = refl
    ⟦⟧-bijective : Bijective ⟦⟧-func
    ⟦⟧-bijective   = record
      { injective  = ⟦⟧-func-injective
      ; surjective = record
        { from             = ⟦⟧-func-inv
        ; right-inverse-of = λ { (_ , T) → ⟦⟧-left-inverse-⟦⟧⁻¹ T }
        }
      }
  open ⟦⟧-Bijective using (⟦⟧-covar ; ⟦⟧-injective) public
  ⟪⟫-contraEnv : ∀ Γ → ContraEnv ⟪ Γ ⟫
  ⟪⟫-contraEnv []      = []
  ⟪⟫-contraEnv (T ∷ Γ) = ctt (⟦⟧-covar T) ∷ ⟪⟫-contraEnv Γ
  ⟦⟧-↑-comm : ∀ T n → ⟦ T ⟧ ↑ n ≡ ⟦ T ⇑ n ⟧
  ⟦⟧-↑-comm ⊤ n = refl
  ⟦⟧-↑-comm (var x) n with n ≤? x
  ... | yes n≤x = refl
  ... | no n>x  = refl
  ⟦⟧-↑-comm (Π<: S ∙ U) n
    rewrite ⟦⟧-↑-comm S n | ⟦⟧-↑-comm U (suc n)
                = refl
  <:∈⇒env-lookup : ∀ {n T Γ} → n <: T ∈ Γ → env-lookup ⟪ Γ ⟫ n ≡ just ⟨A: ⊥ ⋯ ⟦ T ⟧ ⟩
  <:∈⇒env-lookup {_} {_} {T ∷ ._} hd
    rewrite ⟦⟧-↑-comm T 0       = refl
  <:∈⇒env-lookup {suc n} {_} {._ ∷ Γ} (tl {_} {T} T∈Γ)
    with lookupOpt ⟪ Γ ⟫ n | <:∈⇒env-lookup T∈Γ
  ...  | nothing           | ()
  ...  | just _            | eq
    rewrite sym $ ⟦⟧-↑-comm T 0 = cong (just ∘ (_↑ 0)) (just-injective eq)
  F<:⇒D<:ᵣ : ∀ {Γ S U} → Γ ⊢F S <: U → ⟪ Γ ⟫ ⊢ᵣ ⟦ S ⟧ <: ⟦ U ⟧
  F<:⇒D<:ᵣ ftop               = drtop (⟦⟧-covar _)
  F<:⇒D<:ᵣ fvrefl             = drrefl (cv∙A _)
  F<:⇒D<:ᵣ (fbinds T∈Γ T<:U)  = drsel (<:∈⇒env-lookup T∈Γ) (⟦⟧-covar _) (F<:⇒D<:ᵣ T<:U)
  F<:⇒D<:ᵣ (fall S′<:S U<:U′) = drall (⟦⟧-covar _) (⟦⟧-covar _) (⟦⟧-covar _) (⟦⟧-covar _)
                                      (F<:⇒D<:ᵣ S′<:S) (F<:⇒D<:ᵣ U<:U′)
  env-lookup⇒<:∈ : ∀ {n T Γ} → env-lookup Γ n ≡ just ⟨A: ⊥ ⋯ T ⟩ →
                   ∀ {Γ′} → Γ ≡ ⟪ Γ′ ⟫ →
                   ∃ λ T′ → T ≡ ⟦ T′ ⟧ × n <: T′ ∈ Γ′
  env-lookup⇒<:∈ T∈Γ eqΓ = aux (lookup⇒↦∈ T∈Γ) refl eqΓ
    where aux : ∀ {n T Γ} → n ↦ T ∈ Γ →
                   ∀ {U Γ′} → T ≡ ⟨A: ⊥ ⋯ U ⟩ → Γ ≡ ⟪ Γ′ ⟫ →
                   ∃ λ U′ → U ≡ ⟦ U′ ⟧ × n <: U′ ∈ Γ′
          aux hd {_} {[]} eqT ()
          aux hd {_} {T ∷ Γ′} refl refl
            rewrite ⟦⟧-↑-comm T 0 = T ⇑ zero , refl , hd
          aux (tl T∈Γ) {_} {[]} eqT ()
          aux (tl {T = ⊤} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = ⊥} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = n ∙A} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = Π S ∙ U} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = ⟨A: ⊤ ⋯ U ⟩} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = ⟨A: ⊥ ⋯ U ⟩} T∈Γ) {_} {_ ∷ Γ′} refl refl
            with aux T∈Γ refl refl
          ...  | U′ , refl , U′∈Γ′
            rewrite ⟦⟧-↑-comm U′ 0 = U′ ⇑ zero , refl , tl U′∈Γ′
          aux (tl {T = ⟨A: _ ∙A ⋯ U ⟩} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = ⟨A: Π _ ∙ _ ⋯ U ⟩} T∈Γ) {_} {_ ∷ Γ′} () refl
          aux (tl {T = ⟨A: ⟨A: _ ⋯ _ ⟩ ⋯ U ⟩} T∈Γ) {_} {_ ∷ Γ′} () refl
  D<:ᵣ⇒F<: : ∀ {Γ′ S′ U′} → Γ′ ⊢ᵣ S′ <: U′ →
            ∀ {Γ S U} →
              Γ′ ≡ ⟪ Γ ⟫ → S′ ≡ ⟦ S ⟧ → U′ ≡ ⟦ U ⟧ →
              Γ ⊢F S <: U
  D<:ᵣ⇒F<: (drtop S′) {Γ} {S} {⊤} eqΓ eqS refl   = ftop
  D<:ᵣ⇒F<: (drtop S′) {Γ} {S} {var x} eqΓ eqS ()
  D<:ᵣ⇒F<: (drtop S′) {Γ} {S} {Π<: U ∙ U₁} eqΓ eqS ()
  D<:ᵣ⇒F<: (drrefl S′) {Γ} {S} {U} eqΓ eqS eqU
    rewrite ⟦⟧-injective (≡.trans (sym eqS) eqU) = <:-refl Γ U
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {⊤} {⊤} eqΓ () eqU
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {⊤} {var x} eqΓ () eqU
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {⊤} {Π<: U ∙ U₁} eqΓ () eqU
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {var _} {⊤} eqΓ () eqU
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {var _} {var _} eqΓ () eqU
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {var _} {Π<: _ ∙ _} eqΓ () eqU
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {Π<: _ ∙ _} {⊤} eqΓ refl ()
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {Π<: _ ∙ _} {var _} eqΓ refl ()
  D<:ᵣ⇒F<: (drall cS cU cS′ cU′ S′<:S U<:U′) {Γ} {Π<: S ∙ U} {Π<: S′ ∙ U′} eqΓ refl refl
    = fall (D<:ᵣ⇒F<: S′<:S eqΓ refl refl)
           (D<:ᵣ⇒F<: U<:U′ (cong (⟨A: ⊥ ⋯ ⟦ S′ ⟧ ⟩ ∷_) eqΓ) refl refl)
  D<:ᵣ⇒F<: (drsel T∈Γ cT S<:U) {Γ} {⊤} {U} eqΓ () eqU
  D<:ᵣ⇒F<: (drsel T∈Γ cT S<:U) {Γ} {var x} {U} eqΓ refl eqU
    with env-lookup⇒<:∈ T∈Γ eqΓ
  ...  | U′ , eqU′ , T′∈Γ = fbinds T′∈Γ (D<:ᵣ⇒F<: S<:U eqΓ eqU′ eqU)
  D<:ᵣ⇒F<: (drsel T∈Γ cT S<:U) {Γ} {Π<: _ ∙ _} {U} eqΓ () eqU