module ITyping where

open import Data.Empty
open import Data.List
open import Data.Nat
open import Data.Product
open import Data.Sum
open import Data.List.Properties
open import Data.List.Any as LAny
open LAny.Membership-≡
open import Relation.Nullary
open import Relation.Binary.Core
open import Relation.Binary.PropositionalEquality using (sym)

open import Core
open import Core-Lemmas
open import Typing
open import Typed-Core
open import ITyping-Core
open import ITyping-Subst

open import Reduction using (_↝_)

subst-⊩ :  {A B Γ τ τᵢ x} {m : Λ A} {n : Λ B} ->
  ΛTerm m ->
  ΛTerm n -> ((x , (τᵢ , B))  Γ)  m  τ -> Γ ⊩ₗ n  τᵢ ->
  Γ  (m Λ[ x ::= n ])  τ
subst-⊩ₗ :  {A B Γ τ τᵢ x} {m : Λ A} {n : Λ B} ->
  ΛTerm m ->
  ΛTerm n ->
  ((x , (τᵢ , B))  Γ) ⊩ₗ m  τ -> Γ ⊩ₗ n  τᵢ ->
  Γ ⊩ₗ (m Λ[ x ::= n ])  τ

subst-⊩ {x = x} var trm-n (var {x = y} wf-Γ τᵢ∈Γ τ⊆τᵢ) Γ⊩ₗn∶τᵢ with x  y
subst-⊩ {A} {B} var trm-n (var (cons x∉ x₂ wf-Γ) (here px) τ⊆τᵢ) Γ⊩ₗn∶τᵢ | yes refl with A ≟T B
subst-⊩ var trm-n (var (cons x∉ x₂ wf-Γ) (here refl) τ⊆τᵢ) Γ⊩ₗn∶τᵢ | yes refl | yes refl =
  ⊩ₗ-∈-⊩ (subₗ Γ⊩ₗn∶τᵢ τ⊆τᵢ (⊆Γ-⊆ wf-Γ  {x} z  z))) (here refl)
subst-⊩ var trm-n (var (cons x∉ x₂ wf-Γ) (here refl) τ⊆τᵢ) Γ⊩ₗn∶τᵢ | yes refl | no A≠B =
  ⊥-elim (A≠B refl)
subst-⊩ var trm-n (var (cons x∉ x₂ wf-Γ) (there τᵢ∈Γ) τ⊆τᵢ) Γ⊩ₗn∶τᵢ | yes refl =
  ⊥-elim (∉-dom x∉ τᵢ∈Γ)
subst-⊩ var trm-n (var (cons x∉ x₂ wf-Γ) (here refl) τ⊆τᵢ) Γ⊩ₗn∶τᵢ | no x≠y =
  ⊥-elim (x≠y refl)
subst-⊩ var trm-n (var (cons x∉ x₂ wf-Γ) (there τᵢ∈Γ) τ⊆τᵢ) Γ⊩ₗn∶τᵢ | no x≠y =
  var wf-Γ τᵢ∈Γ τ⊆τᵢ
subst-⊩ var trm-n (~>∩ x y z) Γ⊩ₗn∶τᵢ =
  ~>∩ (subst-⊩ var trm-n x Γ⊩ₗn∶τᵢ) (subst-⊩ var trm-n y Γ⊩ₗn∶τᵢ) z
subst-⊩ {B = B} {Γ} {τᵢ = τᵢ} {x} {n = n} (lam L cf) trm-n (abs {A} {τ = τ} {τ'} L' {m} cf') Γ⊩ₗn∶τᵢ =
  abs (x  L ++ L' ++ dom Γ) body

  where
  cons' :  {x τ A Γ} -> Wf-ICtxt ((x , τ , A)  Γ) -> τ ∷'ₗ A
  cons' (cons _ x _) = x

  τ∷ :  {x} -> x  L' -> τ ∷'ₗ A
  τ∷ x∉ = cons' (⊩ₗ-wf-Γ (cf' x∉))

  body :  {x'} -> x'  x  L ++ L' ++ dom Γ ->
    ((x' , τ , A)  Γ) ⊩ₗ Λ[ 0 >> (fv {A} x') ] (m Λ[ x ::= n ])  τ'
  body {x'} x'∉ rewrite
    Λsubst-open-var {τ'' = A} x' x n m (fv-x≠y _ _ x'∉) trm-n = subst-⊩ₗ {τᵢ = τᵢ}
    (cf (∉-∷-elim _ (∉-cons-l _ _ x'∉)))
    trm-n
    (exchange-⊩ₗ (cf' (∉-cons-l _ _ (∉-cons-r L _ (∉-∷-elim _ x'∉)))))
    (subₗ
      Γ⊩ₗn∶τᵢ
      (⊆ₗ-refl (⊩ₗ-∷'ₗ Γ⊩ₗn∶τᵢ))
      (⊆Γ-⊆
        (cons (∉-cons-r L' _ (∉-cons-r L _ (∉-∷-elim _ x'∉)))
              (τ∷ (∉-cons-l L' _ (∉-cons-r L _ (∉-∷-elim _ x'∉))))
              (⊩ₗ-wf-Γ Γ⊩ₗn∶τᵢ))
         {x₂}  there)))

subst-⊩ (lam L cf) trm-n (~>∩ x∷Γ⊩m∶τ x∷Γ⊩m∶τ₁ x₁) Γ⊩ₗn∶τᵢ = ~>∩
  (subst-⊩ (lam L cf) trm-n x∷Γ⊩m∶τ Γ⊩ₗn∶τᵢ)
  (subst-⊩ (lam L cf) trm-n x∷Γ⊩m∶τ₁ Γ⊩ₗn∶τᵢ)
  x₁
subst-⊩ (app trm-m trm-m₁) trm-n (app x∷Γ⊩m∶τ x₁ x₂) Γ⊩ₗn∶τᵢ =
  app (subst-⊩ trm-m trm-n x∷Γ⊩m∶τ Γ⊩ₗn∶τᵢ) (subst-⊩ₗ trm-m₁ trm-n x₁ Γ⊩ₗn∶τᵢ) x₂
subst-⊩ (app trm-m trm-m₁) trm-n (~>∩ x∷Γ⊩m∶τ x∷Γ⊩m∶τ₁ x₁) Γ⊩ₗn∶τᵢ = ~>∩
  (subst-⊩ (app trm-m trm-m₁) trm-n x∷Γ⊩m∶τ Γ⊩ₗn∶τᵢ)
  (subst-⊩ (app trm-m trm-m₁) trm-n x∷Γ⊩m∶τ₁ Γ⊩ₗn∶τᵢ)
  x₁
subst-⊩ Y trm-n (Y (cons x∉ x₁ wf-Γ) x₂ x₃) Γ⊩ₗn∶τᵢ = Y wf-Γ x₂ x₃
subst-⊩ Y trm-n (~>∩ x∷Γ⊩m∶τ x∷Γ⊩m∶τ₁ x₁) Γ⊩ₗn∶τᵢ =
  ~>∩ (subst-⊩ Y trm-n x∷Γ⊩m∶τ Γ⊩ₗn∶τᵢ) (subst-⊩ Y trm-n x∷Γ⊩m∶τ₁ Γ⊩ₗn∶τᵢ) x₁

subst-⊩ₗ trm-m trm-n (nil (cons x∉ x₁ wf-Γ)) Γ⊩ₗn∶τᵢ = nil wf-Γ
subst-⊩ₗ trm-m trm-n (cons x₁ x∷Γ⊩ₗm∶τ) Γ⊩ₗn∶τᵢ = cons
  (subst-⊩ trm-m trm-n x₁ Γ⊩ₗn∶τᵢ)
  (subst-⊩ₗ trm-m trm-n x∷Γ⊩ₗm∶τ Γ⊩ₗn∶τᵢ)
------------------------------------------------------------------------------------

^-⊩ :  {A B Γ τ τᵢ} {m : Λ B} {n : Λ A} -> ΛTerm (lam A m) -> ΛTerm n ->
  Γ  lam A m  (τᵢ ~> ∩' τ) -> Γ ⊩ₗ n  τᵢ ->
  Γ  (Λ[ 0 >> n ] m)  τ
^-⊩ {A} {Γ = Γ} {τ} {τᵢ} {m} {n} (lam L cf) trm-n Γ⊩lam-m Γ⊩n = body
  where
  helper :  L -> (  {x} -> (x∉L : x  L) ->
    ((x , (τᵢ , A))  Γ) ⊩ₗ Λ[ 0 >> fv {A} x ] m  ∩' τ ))
  helper = abs-inv Γ⊩lam-m

  L' = proj₁ helper
  cf' = proj₂ helper

  x = ∃fresh (L ++ L' ++ ΛFV m)

  x∉ : x  (L ++ L' ++ ΛFV m)
  x∉ = ∃fresh-spec (L ++ L' ++ ΛFV m)

  body : Γ  (Λ[ 0 >> n ] m)  τ
  body rewrite
    Λsubst-intro x n m (∉-cons-r L' _ (∉-cons-r L _ x∉)) trm-n =
    subst-⊩ (cf (∉-cons-l L _ x∉))
            trm-n
            (⊩ₗ-∈-⊩ (cf' (∉-cons-l L' _ (∉-cons-r L _ x∉))) (here refl))
            Γ⊩n
------------------------------------------------------------------------------------

Γ⊩Ym∶τ->Γ⊩mYm∶τ :  {A Γ m τ} -> Γ  app (Y A) m  τ -> Γ  app m (app (Y A) m)  τ
Γ⊩Ym∶τ->Γ⊩mYm∶τ {A} {Γ} {m} {τ} (app {τ₁ = τ₁} {τ₂} Γ⊩Y Γ⊩m τ⊆ₗτ₂) =
  app (⊩ₗ-∈-⊩ Γ⊩m' (here refl)) (helper₂ _  {x} z  z)) τ⊆ₗτ'

  where
  helper :   τ  (∩' (τ ~> τ) ⊆ₗ[ A  A ] τ₁) × (τ₂ ⊆ₗ[ A ] τ))
  helper = Y-inv Γ⊩Y

  τ' = proj₁ helper
  τ'~>τ'⊆ₗτ₁ = proj₁ (proj₂ helper)
  τ₂⊆ₗτ' = proj₂ (proj₂ helper)

  τ⊆ₗτ' : (∩' τ) ⊆ₗ[ A ] τ'
  τ⊆ₗτ' = (⊆ₗ-trans τ⊆ₗτ₂ τ₂⊆ₗτ')

  Γ⊩m' : Γ ⊩ₗ m  ∩' (τ' ~> τ')
  Γ⊩m' = subₗ Γ⊩m τ'~>τ'⊆ₗτ₁ (⊆Γ-⊆ (⊩-wf-Γ Γ⊩Y)  {x} z  z))

  helper₂ :  τ -> τ  τ' -> Γ ⊩ₗ app (Y A) m  τ
  helper₂ [] _ = nil (⊩-wf-Γ Γ⊩Y)
  helper₂ (τ  τ'ᵢ) τ⊆τ' = cons
    (app
      (Y (⊩-wf-Γ Γ⊩Y) (⊆ₗ-refl (⊆ₗ-∷'ₗ-l τ'~>τ'⊆ₗτ₁)) (⊆ₗ-refl (⊆ₗ-∷'ₗ-r τ₂⊆ₗτ')))
      Γ⊩m'
      (⊆ₗ-⊆  x₁  τ⊆τ' (∈-∨-++ (inj₁ x₁))) (⊆ₗ-∷'ₗ-r τ₂⊆ₗτ')))
    (helper₂ τ'ᵢ  x₁  τ⊆τ' (there x₁)))

Γ⊩Ym∶τ->Γ⊩mYm∶τ (~>∩ Γ⊩Ym∶τ Γ⊩Ym∶τ₁ x) =
  ~>∩ (Γ⊩Ym∶τ->Γ⊩mYm∶τ Γ⊩Ym∶τ) (Γ⊩Ym∶τ->Γ⊩mYm∶τ Γ⊩Ym∶τ₁) x
------------------------------------------------------------------------------------

->β⊩ :  {A Γ} {m m' : Λ A} {τ} -> Γ  m  τ -> m ->Λβ m' -> Γ  m'  τ
->β⊩ₗ :  {A Γ} {m m' : Λ A} {τ} -> Γ ⊩ₗ m  τ -> m ->Λβ m' -> Γ ⊩ₗ m'  τ

->β⊩ (app Γ⊩m∶τ x x₁) (redL x₃ m->βm') = app (->β⊩ Γ⊩m∶τ m->βm') x x₁
->β⊩ (~>∩ Γ⊩m∶τ Γ⊩m∶τ₁ x) (redL x₁ m->βm') =
  ~>∩ (->β⊩ Γ⊩m∶τ (redL x₁ m->βm')) (->β⊩ Γ⊩m∶τ₁ (redL x₁ m->βm')) x
->β⊩ (app Γ⊩m∶τ x x₁) (redR x₃ m->βm') = app Γ⊩m∶τ (->β⊩ₗ x m->βm') x₁
->β⊩ (~>∩ Γ⊩m∶τ Γ⊩m∶τ₁ x) (redR x₁ m->βm') =
  ~>∩ (->β⊩ Γ⊩m∶τ (redR x₁ m->βm')) (->β⊩ Γ⊩m∶τ₁ (redR x₁ m->βm')) x
->β⊩ (abs L cf) (abs L₁ x₁) =
  abs (L ++ L₁)  x∉L  ->β⊩ₗ (cf (∉-cons-l L _ x∉L)) (x₁ (∉-cons-r L _ x∉L)))
->β⊩ (~>∩ Γ⊩m∶τ Γ⊩m∶τ₁ x) (abs L x₁) =
  ~>∩ (->β⊩ Γ⊩m∶τ (abs L x₁)) (->β⊩ Γ⊩m∶τ₁ (abs L x₁)) x
->β⊩ (app Γ⊩m∶τ Γ⊩ₗn x₁) (beta x₃ x₄) = ^-⊩
  x₃
  x₄
  (sub Γ⊩m∶τ (arr (⊆ₗ-refl (⊩ₗ-∷'ₗ Γ⊩ₗn)) x₁) (⊆Γ-⊆ (⊩-wf-Γ Γ⊩m∶τ)  {x} z  z)))
  Γ⊩ₗn
->β⊩ (~>∩ Γ⊩m∶τ Γ⊩m∶τ₁ x) (beta x₁ x₂) =
  ~>∩ (->β⊩ Γ⊩m∶τ (beta x₁ x₂)) (->β⊩ Γ⊩m∶τ₁ (beta x₁ x₂)) x
->β⊩ {_} {Γ} {τ = τ} Γ⊩m∶τ (Y {A} {m} x) = Γ⊩Ym∶τ->Γ⊩mYm∶τ Γ⊩m∶τ

->β⊩ₗ (nil wf-Γ) m->βm' = nil wf-Γ
->β⊩ₗ (cons x Γ⊩ₗm∶τ) m->βm' = cons (->β⊩ x m->βm') (->β⊩ₗ Γ⊩ₗm∶τ m->βm')
------------------------------------------------------------------------------------

^-⊩-2 :  {A B Γ τ} {m : Λ B} {n : Λ A} -> ΛTerm (lam A m) -> ΛTerm n ->
  Γ  (Λ[ 0 >> n ] m)  τ ->
   τᵢ -> (Γ  lam A m  (τᵢ ~> ∩' τ) × ( Γ ⊩ₗ n  τᵢ )))
^-⊩-2 {A} {B} {Γ} {τ} {m} {n} (lam L cf) trm-n Γ⊩m^n∶τ =
  τᵢ ,
  ((abs
    (x  dom Γ ++ ΛFV m)
     {x'} x'∉  auxₗ
      m
      (proj₂ (∃~T m))
      (∉-cons-l (dom Γ) _ (∉-∷-elim _ x'∉))
      (∉-cons-l (ΛFV m) _ (∉-cons-r L _ x∉))
      ((∉-cons-r (dom Γ) _ (∉-∷-elim _ x'∉)))
       x₁  fv-x≠y _ _ x'∉ (sym x₁))
      (cons
        x∷Γ⊩m^'x∶τ
        (nil (cons (∉-cons-r (ΛFV m) _ (∉-cons-r L _ x∉))
                   (⊩ₗ-∷'ₗ Γ⊩ₗn∶τᵢ)
                   (⊩ₗ-wf-Γ Γ⊩ₗn∶τᵢ)))))) ,
  Γ⊩ₗn∶τᵢ)
  where
  x = ∃fresh (L ++ ΛFV m ++ dom Γ)

  x∉ : x  (L ++ ΛFV m ++ dom Γ)
  x∉ = ∃fresh-spec (L ++ ΛFV m ++ dom Γ)

  Γ⊩m^n∶τ' : Γ  ((Λ[ 0 >> fv {A} x ] m) Λ[ x ::= n ])  τ
  Γ⊩m^n∶τ' rewrite Λsubst-intro2 x n m (∉-cons-l (ΛFV m) _ (∉-cons-r L _ x∉)) trm-n =
    Γ⊩m^n∶τ

  ih :  τᵢ ->
    ( ((x , τᵢ , A)  Γ)  (Λ[ 0 >> fv {A} x ] m)  τ ) × ( Γ ⊩ₗ n  τᵢ ))
  ih = subst-⊩-2
    (cf (∉-cons-l L _ x∉))
    trm-n
    (∉-cons-r (ΛFV m) _ (∉-cons-r L _ x∉))
    Γ⊩m^n∶τ'

  τᵢ = proj₁ ih
  x∷Γ⊩m^'x∶τ = proj₁ (proj₂ ih)
  Γ⊩ₗn∶τᵢ = proj₂ (proj₂ ih)
------------------------------------------------------------------------------------

Γ⊩Ym-max :  {A Γ} {m : Λ (A  A)} {τ} -> Γ  app (Y A) m  τ ->
   τ' -> Γ ⊩ₗ m  ∩' (τ' ~> τ') × (∩' τ) ⊆ₗ[ A ] τ')
Γ⊩Ym-max {A} {Γ} {m} {τ} (app Γ⊩Y∶τ₁~>τ₂ Γ⊩ₗm∶τ₁ τ⊆ₗτ₂) =
  τ' ,
  (subₗ Γ⊩ₗm∶τ₁ τ'~>τ'⊆ₗτ₁ (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗm∶τ₁)  {x} z  z)) ,
  ⊆ₗ-trans τ⊆ₗτ₂ τ₂⊆ₗτ)

  where
  body = Y-inv Γ⊩Y∶τ₁~>τ₂
  τ' = proj₁ body
  τ'~>τ'⊆ₗτ₁ = proj₁ (proj₂ body)
  τ₂⊆ₗτ = proj₂ (proj₂ body)

Γ⊩Ym-max {A  B} {Γ} {m} (~>∩ {τ = τ} {τ₁} {τ₂} {τ₁τ₂} Γ⊩Ym∶τ~>τ₁ Γ⊩Ym∶τ~>τ₂ τ₁τ₂⊆ₗτ₁++τ₂) =
  (τ₁' ++ τ₂') ,
  (subₗ (cons (⊩ₗ-∈-⊩ Γ⊩ₗm∶τ₁'~>τ₁' (here refl)) Γ⊩ₗm∶τ₂'~>τ₂')
        (~>∩' τ₁'∷ τ₂'∷)
        (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗm∶τ₁'~>τ₁')  {x} z  z)) ,
  ⊆ₗ-trans
    (⊆ₗ-trans
      (cons ((τ ~> (τ₁ ++ τ₂)) , ((here refl) , (arr (⊆ₗ-refl τ∷') τ₁τ₂⊆ₗτ₁++τ₂)))
            (nil τ+∷))
      (~>∩ τ+∷))
    (mon τ~>τ₁⊆ₗτ₁' τ~>τ₂⊆ₗτ₂'))

  where
  ihₗ :  τ₁' -> Γ ⊩ₗ m  ∩' (τ₁' ~> τ₁') × (∩' (τ ~> τ₁)) ⊆ₗ[ A  B ] τ₁')
  ihₗ = Γ⊩Ym-max Γ⊩Ym∶τ~>τ₁

  τ₁' = proj₁ ihₗ
  Γ⊩ₗm∶τ₁'~>τ₁' = proj₁ (proj₂ ihₗ)
  τ~>τ₁⊆ₗτ₁' = proj₂ (proj₂ ihₗ)

  ihᵣ :  τ₂' -> Γ ⊩ₗ m  ∩' (τ₂' ~> τ₂') × (∩' (τ ~> τ₂)) ⊆ₗ[ A  B ] τ₂')
  ihᵣ = Γ⊩Ym-max Γ⊩Ym∶τ~>τ₂

  τ₂' = proj₁ ihᵣ
  Γ⊩ₗm∶τ₂'~>τ₂' = proj₁ (proj₂ ihᵣ)
  τ~>τ₂⊆ₗτ₂' = proj₂ (proj₂ ihᵣ)

  τ₁'∷ = ⊆ₗ-∷'ₗ-r τ~>τ₁⊆ₗτ₁'
  τ₂'∷ = ⊆ₗ-∷'ₗ-r τ~>τ₂⊆ₗτ₂'
  τ∷' = proj₁ (arr' (⊩-∷' Γ⊩Ym∶τ~>τ₂))

  τ₁τ₂∷' = ⊆ₗ-∷'ₗ-l τ₁τ₂⊆ₗτ₁++τ₂
  τ₁++τ₂∷' = ⊆ₗ-∷'ₗ-r τ₁τ₂⊆ₗτ₁++τ₂

  τ+∷ : ((τ ~> (τ₁ ++ τ₂))  []) ∷'ₗ (A  B)
  τ+∷ = cons (arr τ∷' τ₁++τ₂∷') nil
------------------------------------------------------------------------------------

¬ω⊆-impl¬ω :  {A τ τ'} -> ¬(τ  ω) -> τ ⊆ₗ[ A ] τ' -> ¬(τ'  ω)
¬ω⊆-impl¬ω τ≠ω (nil x) τ'≡ω = τ≠ω refl
¬ω⊆-impl¬ω τ≠ω (cons (_ , () , _) τ⊆ₗτ') refl
¬ω⊆-impl¬ω τ≠ω (~>∩ x) ()
¬ω⊆-impl¬ω τ≠ω (⊆ₗ-trans τ⊆ₗτ' τ⊆ₗτ'') τ'≡ω =
  ¬ω⊆-impl¬ω (¬ω⊆-impl¬ω τ≠ω τ⊆ₗτ') τ⊆ₗτ'' τ'≡ω
------------------------------------------------------------------------------------

Γ⊩ₗYm-max :  {A Γ} {m : Λ (A  A)} {τ} -> ¬(τ  ω) -> Γ ⊩ₗ app (Y A) m  τ ->
   τ' -> Γ ⊩ₗ m  ∩' (τ' ~> τ') × τ ⊆ₗ[ A ] τ')
Γ⊩ₗYm-max τ≠ω (nil wf-Γ) = ⊥-elim (τ≠ω refl)
Γ⊩ₗYm-max {A} {Γ} {m} {τ  τᵢ} τ≠ω (cons x Γ⊩ₗYm∶τ) with τᵢ ≟TIₗ ω
Γ⊩ₗYm-max {A} {Γ} {m} {τ  .[]} τ≠ω (cons x Γ⊩ₗYm∶τ) | yes refl = Γ⊩Ym-max x
Γ⊩ₗYm-max {A} {Γ} {m} {τ  τᵢ} τ≠ω (cons x Γ⊩ₗYm∶τ) | no τᵢ≠ω =
  τ' ++ τᵢ' ,
  subₗ Γ⊩ₗm∶ττᵢ'~>τ'ττᵢ'~>τᵢ'
       (~>∩ (cons (arr (∷'ₗ-++ τ'∷'A τᵢ'∷'A) (∷'ₗ-++ τ'∷'A τᵢ'∷'A)) nil))
       (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗYm∶τ)  {x} z  z)) ,
  mon τ⊆τ' τᵢ⊆τᵢ'
  where
  ih :  τᵢ' -> Γ ⊩ₗ m  ∩' (τᵢ' ~> τᵢ') × τᵢ ⊆ₗ[ A ] τᵢ')
  ih = Γ⊩ₗYm-max τᵢ≠ω Γ⊩ₗYm∶τ

  τᵢ' = proj₁ ih
  Γ⊩ₗm∶τᵢ'~>τᵢ' : Γ ⊩ₗ m  ∩' (τᵢ' ~> τᵢ')
  Γ⊩ₗm∶τᵢ'~>τᵢ' = proj₁ (proj₂ ih)

  τᵢ⊆τᵢ' = proj₂ (proj₂ ih)

  body :  τ' -> Γ ⊩ₗ m  ∩' (τ' ~> τ') × ∩' τ ⊆ₗ[ A ] τ')
  body = Γ⊩Ym-max x

  τ' = proj₁ body
  Γ⊩ₗm∶τ'~>τ' : Γ ⊩ₗ m  ∩' (τ' ~> τ')
  Γ⊩ₗm∶τ'~>τ' = proj₁ (proj₂ body)

  τ⊆τ' = proj₂ (proj₂ body)

  τ'∷'A = ⊆ₗ-∷'ₗ-r τ⊆τ'
  τᵢ'∷'A = ⊆ₗ-∷'ₗ-r τᵢ⊆τᵢ'

  Γ⊩ₗm∶ττᵢ'~>τ'ττᵢ'~>τᵢ' :
    Γ ⊩ₗ m  (∩' ((τ' ++ τᵢ') ~> τ') ++ ∩' ((τ' ++ τᵢ') ~> τᵢ'))
  Γ⊩ₗm∶ττᵢ'~>τ'ττᵢ'~>τᵢ' =
    ⊩++ {τᵢ = ∩' ((τ' ++ τᵢ') ~> τ')} {∩' ((τ' ++ τᵢ') ~> τᵢ')}
      (subₗ Γ⊩ₗm∶τ'~>τ'
        (cons
          ( (τ' ~> τ') ,
            (here refl ,
            arr (⊆ₗ-⊆  x₂  ∈-cons-l _ x₂) (∷'ₗ-++ τ'∷'A τᵢ'∷'A))
                (⊆ₗ-refl τ'∷'A)))
          (nil (cons (arr τ'∷'A τ'∷'A) nil)))
        (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗYm∶τ)  {x} z  z)))
      (subₗ Γ⊩ₗm∶τᵢ'~>τᵢ'
        (cons
          ( (τᵢ' ~> τᵢ') ,
            (here refl ,
            arr (⊆ₗ-⊆  x₂  ∈-cons-r τ' x₂) (∷'ₗ-++ τ'∷'A τᵢ'∷'A))
                (⊆ₗ-refl τᵢ'∷'A)))
          (nil (cons (arr τᵢ'∷'A τᵢ'∷'A) nil)))
        (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗYm∶τ)  {x} z  z)))
------------------------------------------------------------------------------------

Γ⊩mYm∶τ->Γ⊩Ym∶τ :  {A Γ m τ} -> Γ  app m (app (Y A) m)  τ ->
  Γ  app (Y A) m  τ
Γ⊩mYm∶τ->Γ⊩Ym∶τ {A} {Γ} {τ = τ} (app {s = m} {τ₁ = []} {τᵢ} Γ⊩m∶τᵢ'~>τᵢ (nil wf-Γ) τ⊆τᵢ) =
  app
    (Y {τ = ∩' τ} {(ω ~> ∩' τ)  []} {∩' τ}
      wf-Γ
      (cons (([] ~> ∩' τ) , (here refl , arr (nil τ∷A) (⊆ₗ-refl τ∷A)))
            (nil (cons (arr nil τ∷A) nil)))
      (⊆ₗ-refl τ∷A))
    (cons (sub Γ⊩m∶τᵢ'~>τᵢ (arr (nil nil) τ⊆τᵢ) (⊆Γ-⊆ wf-Γ  {x} z  z)))
          (nil wf-Γ))
    (⊆ₗ-refl τ∷A)

  where
  τ∷A = ⊆ₗ-∷'ₗ-l τ⊆τᵢ

Γ⊩mYm∶τ->Γ⊩Ym∶τ {A} {Γ} {τ = τ} (app {s = m} {τ₁ = τ'  τᵢ'} {τᵢ} Γ⊩m∶τᵢ'~>τᵢ (cons x₁ Γ⊩ₗYm∶τ'ᵢ₁) τ⊆τᵢ) =
  app
    (Y {τ = [ τ ] ++ τ''} {∩' (τ'' ~> ([ τ ] ++ τ''))} {∩' τ}
      (⊩ₗ-wf-Γ Γ⊩ₗYm∶τ'ᵢ₁)
      (cons (τ'' ~> ([ τ ] ++ τ'') ,
            here refl ,
            arr (⊆ₗ-⊆  x₂  ∈-cons-r [ τ ] x₂) (cons τ∷'A τ''∷'A))
                (⊆ₗ-refl (cons τ∷'A τ''∷'A)))
            (nil (cons (arr τ''∷'A (cons τ∷'A τ''∷'A)) nil)))
    (cons (τ , (here refl , ⊆-refl τ∷'A)) (nil (cons τ∷'A τ''∷'A))))
  Γ⊩ₗm∶τ''~>τ∷τ''
  (⊆ₗ-refl (cons τ∷'A nil))

  where
  τᵢ'' = τ'  τᵢ'
  body₁ :  τ'' -> Γ ⊩ₗ m  ∩' (τ'' ~> τ'') × τᵢ'' ⊆ₗ[ A ] τ'')
  body₁ = Γ⊩ₗYm-max  ()) (cons x₁ Γ⊩ₗYm∶τ'ᵢ₁)

  τ'' = proj₁ body₁

  Γ⊩ₗm∶τ''~>τ'' : Γ ⊩ₗ m  ∩' (τ'' ~> τ'')
  Γ⊩ₗm∶τ''~>τ'' = proj₁ (proj₂ body₁)

  τᵢ''⊆τ'' = proj₂ (proj₂ body₁)
  τ''∷'A = ⊆ₗ-∷'ₗ-r τᵢ''⊆τ''
  τᵢ''∷'A = ⊆ₗ-∷'ₗ-l τᵢ''⊆τ''

  τ∷'A : τ ∷' A
  τ∷'A = ∷'ₗ-∈ (here refl) (⊆ₗ-∷'ₗ-l τ⊆τᵢ)

  Γ⊩m∶τ''~>τ : Γ  m  (τ'' ~> ∩' τ)
  Γ⊩m∶τ''~>τ = sub Γ⊩m∶τᵢ'~>τᵢ
                   (arr τᵢ''⊆τ'' τ⊆τᵢ)
                   (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗYm∶τ'ᵢ₁)  {x} z  z))

  Γ⊩ₗm∶τ''~>τ∷τ'' : Γ ⊩ₗ m  ∩' (τ'' ~> (τ  τ''))
  Γ⊩ₗm∶τ''~>τ∷τ'' = subₗ (cons Γ⊩m∶τ''~>τ Γ⊩ₗm∶τ''~>τ'')
                         (~>∩ (cons (arr τ''∷'A (cons τ∷'A τ''∷'A)) nil))
                         (⊆Γ-⊆ (⊩ₗ-wf-Γ Γ⊩ₗYm∶τ'ᵢ₁)  {x} z  z))

Γ⊩mYm∶τ->Γ⊩Ym∶τ (~>∩ Γ⊩mYm∶τ Γ⊩mYm∶τ₁ z) =
  ~>∩ (Γ⊩mYm∶τ->Γ⊩Ym∶τ Γ⊩mYm∶τ) (Γ⊩mYm∶τ->Γ⊩Ym∶τ Γ⊩mYm∶τ₁) z
------------------------------------------------------------------------------------

⊩->β :  {A Γ} {m m' : Λ A} {τ} -> Γ  m'  τ -> m ->Λβ m' -> Γ  m  τ
⊩->βₗ :  {A Γ} {m m' : Λ A} {τ} -> Γ ⊩ₗ m'  τ -> m ->Λβ m' -> Γ ⊩ₗ m  τ

⊩->β Γ⊩m'∶τ (redL x m->βm') = ⊩->β-redL Γ⊩m'∶τ m->βm'
  where
  ⊩->β-redL :  {A B Γ} {m m' : Λ (A  B)} {n : Λ A} {τ} ->
    Γ  app m' n  τ -> m ->Λβ m' -> Γ  app m n  τ
  ⊩->β-redL (app Γ⊩m'n∶τ x₁ x₂) (redL x₄ m->Λβm') =
    app (⊩->β-redL Γ⊩m'n∶τ m->Λβm') x₁ x₂
  ⊩->β-redL (~>∩ Γ⊩m'n∶τ Γ⊩m'n∶τ₁ x₁) (redL x₂ m->Λβm') =
    ~>∩ (⊩->β-redL Γ⊩m'n∶τ (redL x₂ m->Λβm'))
        (⊩->β-redL Γ⊩m'n∶τ₁ (redL x₂ m->Λβm'))
        x₁
  ⊩->β-redL (app Γ⊩m'n∶τ x₁ x₂) (redR x₄ m->Λβm') =
    app (⊩->β Γ⊩m'n∶τ (redR x₄ m->Λβm')) x₁ x₂
  ⊩->β-redL (~>∩ Γ⊩m'n∶τ Γ⊩m'n∶τ₁ x₁) (redR x₂ m->Λβm') =
    ~>∩ (⊩->β-redL Γ⊩m'n∶τ (redR x₂ m->Λβm'))
        (⊩->β-redL Γ⊩m'n∶τ₁ (redR x₂ m->Λβm'))
        x₁
  ⊩->β-redL (app Γ⊩m'n∶τ x₁ x₂) (abs L x₄) = app (⊩->β Γ⊩m'n∶τ (abs L x₄)) x₁ x₂
  ⊩->β-redL (~>∩ Γ⊩m'n∶τ Γ⊩m'n∶τ₁ x₁) (abs L x₂) =
    ~>∩ (⊩->β-redL Γ⊩m'n∶τ (abs L x₂)) (⊩->β-redL Γ⊩m'n∶τ₁ (abs L x₂)) x₁
  ⊩->β-redL (app Γ⊩m'n∶τ x₁ x₂) (beta x₄ x₅) =
    app (⊩->β Γ⊩m'n∶τ (beta x₄ x₅)) x₁ x₂
  ⊩->β-redL (~>∩ Γ⊩m'n∶τ Γ⊩m'n∶τ₁ x₁) (beta x₂ x₃) =
    ~>∩ (⊩->β-redL Γ⊩m'n∶τ (beta x₂ x₃)) (⊩->β-redL Γ⊩m'n∶τ₁ (beta x₂ x₃)) x₁
  ⊩->β-redL (app Γ⊩m'n∶τ x₁ x₂) (Y x₄) = app (⊩->β Γ⊩m'n∶τ (Y x₄)) x₁ x₂
  ⊩->β-redL (~>∩ Γ⊩m'n∶τ Γ⊩m'n∶τ₁ x₁) (Y x₂) =
    ~>∩ (⊩->β-redL Γ⊩m'n∶τ (Y x₂)) (⊩->β-redL Γ⊩m'n∶τ₁ (Y x₂)) x₁

⊩->β (app Γ⊩m'∶τ x x₁) (redR x₃ m->βm') = app Γ⊩m'∶τ (⊩->βₗ x m->βm') x₁
⊩->β (~>∩ Γ⊩m'∶τ Γ⊩m'∶τ₁ x) (redR x₁ m->βm') =
  ~>∩ (⊩->β Γ⊩m'∶τ (redR x₁ m->βm')) (⊩->β Γ⊩m'∶τ₁ (redR x₁ m->βm')) x
⊩->β (abs L cf) (abs L₁ x₁) =
  abs (L ++ L₁)  x∉L  ⊩->βₗ (cf (∉-cons-l _ _ x∉L)) (x₁ (∉-cons-r L _ x∉L)))
⊩->β (~>∩ Γ⊩m'∶τ Γ⊩m'∶τ₁ x) (abs L x₁) =
  ~>∩ (⊩->β Γ⊩m'∶τ (abs L x₁)) (⊩->β Γ⊩m'∶τ₁ (abs L x₁)) x
⊩->β Γ⊩m'∶τ (beta {m = m} {n} x x₁) =
  app Γ⊩lam-m∶τ Γ⊩ₗn∶τᵢ (⊆ₗ-refl (cons (⊩-∷' Γ⊩m'∶τ) nil))
  
  where
  helper = ^-⊩-2 x x₁ Γ⊩m'∶τ
  τᵢ = proj₁ helper
  Γ⊩lam-m∶τ = proj₁ (proj₂ helper)
  Γ⊩ₗn∶τᵢ = proj₂ (proj₂ helper)
⊩->β Γ⊩mYm∶τ (Y _) = Γ⊩mYm∶τ->Γ⊩Ym∶τ Γ⊩mYm∶τ

⊩->βₗ (nil wf-Γ) m->βm' = nil wf-Γ
⊩->βₗ (cons x Γ⊩ₗm'∶τ) m->βm' = cons (⊩->β x m->βm') (⊩->βₗ Γ⊩ₗm'∶τ m->βm')