{-# OPTIONS --safe #-}
module Cubical.Relation.Binary.Order.Poset.Instances.Embedding where

open import Cubical.Foundations.Equiv
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Prelude

open import Cubical.Data.Sum as 
open import Cubical.Data.Empty as 

open import Cubical.Functions.Embedding

open import Cubical.HITs.PropositionalTruncation as ∥₁

open import Cubical.Relation.Binary.Order.Proset.Properties
open import Cubical.Relation.Binary.Order.Poset.Base
open import Cubical.Relation.Binary.Order.Poset.Properties

private
  variable
     ℓ' : Level

-- The collection of embeddings on a type happens to form a complete lattice

-- First, we show that it's a poset
isPoset⊆ₑ : {A : Type }  IsPoset {A = Embedding A ℓ'} _⊆ₑ_
isPoset⊆ₑ = isposet isSetEmbedding
                    isProp⊆ₑ
                    isRefl⊆ₑ
                    isTrans⊆ₑ
                    isAntisym⊆ₑ

EmbeddingPoset : (A : Type ) (ℓ' : Level)  Poset _ _
EmbeddingPoset A ℓ'
  = poset (Embedding A ℓ') _⊆ₑ_ (isPoset⊆ₑ)

-- Then we describe it as both a lattice and a complete lattice
isMeet∩ₑ : {A : Type }
           (X Y : Embedding A )
          isMeet (isPoset→isProset isPoset⊆ₑ) X Y (X ∩ₑ Y)
isMeet∩ₑ X Y Z = propBiimpl→Equiv (isProp⊆ₑ Z (X ∩ₑ Y))
                                  (isProp× (isProp⊆ₑ Z X)
                                  (isProp⊆ₑ Z Y))
                                   Z⊆X∩Y 
                                     x x∈Z 
                                       subst (_∈ₑ X)
                                             (Z⊆X∩Y x x∈Z .snd)
                                             (Z⊆X∩Y x x∈Z .fst .snd .fst)) ,
                                     x x∈Z 
                                       subst (_∈ₑ Y)
                                             (Z⊆X∩Y x x∈Z .snd)
                                             (Z⊆X∩Y x x∈Z .fst .snd .snd)))
                                   λ { (Z⊆X , Z⊆Y) x x∈Z 
                                       (x , ((Z⊆X x x∈Z) ,
                                             (Z⊆Y x x∈Z))) , refl }

isMeetSemipseudolatticeEmbeddingPoset : {A : Type }
                                       isMeetSemipseudolattice (EmbeddingPoset A )
isMeetSemipseudolatticeEmbeddingPoset X Y
  = X ∩ₑ Y , isMeet∩ₑ X Y

isGreatestEmbeddingPosetTotal : {A : Type }
                               isGreatest (isPoset→isProset isPoset⊆ₑ)
                                           (Embedding A  , id↪ (Embedding A ))
                                           (A , (id↪ A))
isGreatestEmbeddingPosetTotal _ x _
  = x , refl

isMeetSemilatticeEmbeddingPoset : {A : Type }
                                 isMeetSemilattice (EmbeddingPoset A )
isMeetSemilatticeEmbeddingPoset {A = A}
  = isMeetSemipseudolatticeEmbeddingPoset ,
    (A , (id↪ A)) ,
    isGreatestEmbeddingPosetTotal

isJoin∪ₑ : {A : Type }
           (X Y : Embedding A )
          isJoin (isPoset→isProset isPoset⊆ₑ) X Y (X ∪ₑ Y)
isJoin∪ₑ X Y Z
  = propBiimpl→Equiv (isProp⊆ₑ (X ∪ₑ Y) Z)
                     (isProp× (isProp⊆ₑ X Z)
                              (isProp⊆ₑ Y Z))
                      X∪Y⊆Z 
                           x x∈X  X∪Y⊆Z x ((x ,  inl x∈X ∣₁) , refl)) ,
                           x x∈Y  X∪Y⊆Z x ((x ,  inr x∈Y ∣₁) , refl)))
                      λ { (X⊆Z , Y⊆Z) x x∈X∪Y 
                          ∥₁.rec (isProp∈ₑ x Z)
                                 (⊎.rec  a∈X  subst (_∈ₑ Z)
                                                       (x∈X∪Y .snd)
                                                       (X⊆Z _ a∈X))
                                         a∈Y  subst (_∈ₑ Z)
                                                       (x∈X∪Y .snd)
                                                       (Y⊆Z _ a∈Y)))
                                 (x∈X∪Y .fst .snd) }

isJoinSemipseudolatticeEmbeddingPoset : {A : Type }
                                       isJoinSemipseudolattice (EmbeddingPoset A )
isJoinSemipseudolatticeEmbeddingPoset X Y
  = X ∪ₑ Y , isJoin∪ₑ X Y

isLeast∅ : {A : Type }
          isLeast (isPoset→isProset isPoset⊆ₑ) (Embedding A  , id↪ (Embedding A )) ((Σ[ x  A ] ) , EmbeddingΣProp λ _  isProp⊥)
isLeast∅ _ _ ((_ , ()) , _)

isJoinSemilatticeEmbeddingPoset : {A : Type }
                                 isJoinSemilattice (EmbeddingPoset A )
isJoinSemilatticeEmbeddingPoset {A = A}
  = isJoinSemipseudolatticeEmbeddingPoset ,
    ((Σ[ x  A ] ) , EmbeddingΣProp λ _  isProp⊥) ,
    isLeast∅

isLatticeEmbeddingPoset : {A : Type }
                         isLattice (EmbeddingPoset A )
isLatticeEmbeddingPoset = isMeetSemilatticeEmbeddingPoset ,
                          isJoinSemilatticeEmbeddingPoset

isInfimum⋂ₑ : {A : Type }
               {I : Type }
               (P : I  Embedding A )
              isInfimum (isPoset→isProset isPoset⊆ₑ) P (⋂ₑ P)
fst (isInfimum⋂ₑ P) i y ((a , ∀i) , a≡y) = subst (_∈ₑ P i) a≡y (∀i i)
snd (isInfimum⋂ₑ P) (X , lwr) y y∈X = (y , λ i  lwr i y y∈X) , refl

isMeetCompleteSemipseudolatticeEmbeddingPoset : {A : Type }
                                               isMeetCompleteSemipseudolattice (EmbeddingPoset A )
isMeetCompleteSemipseudolatticeEmbeddingPoset P
  = (⋂ₑ P) , (isInfimum⋂ₑ P)

isSupremum⋃ₑ : {A : Type }
               {I : Type }
               (P : I  Embedding A )
               isSupremum (isPoset→isProset isPoset⊆ₑ) P (⋃ₑ P)
fst (isSupremum⋃ₑ P) i y y∈Pi = (y ,  i , y∈Pi ∣₁) , refl
snd (isSupremum⋃ₑ P) (X , upr) y ((a , ∃i) , a≡y)
  = ∥₁.rec (isProp∈ₑ y X)  (i , a∈Pi)  upr i y (subst (_∈ₑ P i) a≡y a∈Pi)) ∃i

isJoinCompleteSemipseudolatticeEmbeddingPoset : {A : Type }
                                               isJoinCompleteSemipseudolattice (EmbeddingPoset A )
isJoinCompleteSemipseudolatticeEmbeddingPoset P
  = (⋃ₑ P) , (isSupremum⋃ₑ P)

isCompleteLatticeEmbeddingPoset : {A : Type }
                                 isCompleteLattice (EmbeddingPoset A )
isCompleteLatticeEmbeddingPoset = isMeetCompleteSemipseudolatticeEmbeddingPoset ,
                                  isJoinCompleteSemipseudolatticeEmbeddingPoset