{-# OPTIONS --cubical --safe #-}

-- The posetal reflection is the universal way to turn a preorder into a poset
-- In abstract-nonsense terms, the posetal reflection exhibits Pos as a reflective subcategory of preorders.
-- https://ncatlab.org/nlab/show/posetal+reflection
-- When a preorder is viewed as a category, posets are univalent categories
-- and the posetal reflection is a special case of the Rezk completion.

module Cubical.Relation.Binary.Order.Poset.Instances.PosetalReflection where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Structure
open import Cubical.Foundations.HLevels
open import Cubical.Functions.Logic
open import Cubical.Functions.Embedding
open import Cubical.HITs.SetQuotients as SetQuot using (_/_; [_]; eq/; squash/)

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

private variable
   ℓ' ℓ'' : Level

module _ (P : Proset  ℓ') where
  open module P = ProsetStr (P .snd) using (_≲_)
  open ProsetReasoning P renaming (_◾ to _≲∎)
  open BinaryRelation

  private variable
    a b c :  P 

  _~_ : Rel  P   P  ℓ'
  _~_ = SymKernel _≲_

  isEquivRel~ : isEquivRel _~_
  isEquivRel~ = isProset→isEquivRelSymKernel P.isProset

  Reflection : Type (ℓ-max  ℓ')
  Reflection =  P  / _~_

  _≤'_ : Reflection  Reflection  hProp ℓ'
  _≤'_ = SetQuot.rec2 isSetHProp  a b  a  b , P.is-prop-valued a b)
     a b c (a≲b , b≲a)  ⇔toPath  a≲c  b ≲⟨ b≲a  a ≲⟨ a≲c  c ≲∎)  b≲c  a ≲⟨ a≲b  b ≲⟨ b≲c  c ≲∎))
     a b c (b≲c , c≲b)  ⇔toPath  a≲b  a ≲⟨ a≲b  b ≲⟨ b≲c  c ≲∎)  a≲c  a ≲⟨ a≲c  c ≲⟨ c≲b  b ≲∎))

  _≤_ : Reflection  Reflection  Type ℓ'
  a  b =  a ≤' b 

  isPropValued≤ : isPropValued _≤_
  isPropValued≤ a b = snd (a ≤' b)

  isRefl≤ : isRefl _≤_
  isRefl≤ = SetQuot.elimProp  a  isPropValued≤ a a) P.is-refl

  isTrans≤ : isTrans _≤_
  isTrans≤ = SetQuot.elimProp3  a b c  isPropΠ2 λ _ _  isPropValued≤ a c) P.is-trans

  isAntisym≤ : isAntisym _≤_
  isAntisym≤ = SetQuot.elimProp2  a b  isPropΠ2 λ _ _  squash/ a b) λ a b a≲b b≲a  eq/ a b (a≲b , b≲a)

  isPoset≤ : IsPoset _≤_
  isPoset≤ .IsPoset.is-set = squash/
  isPoset≤ .IsPoset.is-prop-valued = isPropValued≤
  isPoset≤ .IsPoset.is-refl = isRefl≤
  isPoset≤ .IsPoset.is-trans = isTrans≤
  isPoset≤ .IsPoset.is-antisym = isAntisym≤

  ReflectionPoset : Poset (ℓ-max  ℓ') ℓ'
  ReflectionPoset = Reflection , posetstr _≤_ isPoset≤

  isProset≤ : IsProset _≤_
  isProset≤ = isPoset→isProset isPoset≤

  private
    idEmb : {A : Type ℓ''}  Embedding A ℓ''
    idEmb = _ , id↪ _

  -- if a preorder is bounded, then so is its posetal reflection

  []presLeast :  least  isLeast P.isProset idEmb least  isLeast isProset≤ idEmb [ least ]
  []presLeast least is-least = SetQuot.elimProp  x  isPropValued≤ [ least ] x) is-least

  hasLeast : Least P.isProset idEmb  Least isProset≤ idEmb
  hasLeast least = [ least .fst ] , []presLeast (least .fst) (least .snd)

  []presGreatest :  greatest  isGreatest P.isProset idEmb greatest  isGreatest isProset≤ idEmb [ greatest ]
  []presGreatest greatest is-greatest = SetQuot.elimProp  x  isPropValued≤ x [ greatest ]) is-greatest

  hasGreatest : Greatest P.isProset idEmb  Greatest isProset≤ idEmb
  hasGreatest greatest = [ greatest .fst ] , []presGreatest (greatest .fst) (greatest .snd)

  -- if a preorder has binary meets, then so does its posetal reflection

  []presMeets :  meet  isMeet P.isProset a b meet  isMeet isProset≤ [ a ] [ b ] [ meet ]
  []presMeets meet is-meet = SetQuot.elimProp  x  isOfHLevel⁺≃ₗ 0 (isPropValued≤ x [ meet ])) is-meet

  []presHasMeet : Meet P.isProset a b  Meet isProset≤ [ a ] [ b ]
  []presHasMeet meet = [ meet .fst ] , []presMeets (meet .fst) (meet .snd)

  hasBinMeets : (∀ a b  Meet P.isProset a b)  isMeetSemipseudolattice ReflectionPoset
  hasBinMeets bin-meets = SetQuot.elimProp2 (MeetUnique isPoset≤) λ a b  []presHasMeet (bin-meets a b)

  -- if a preorder has binary joins, then so does its posetal reflection

  []presJoins :  join  isJoin P.isProset a b join  isJoin isProset≤ [ a ] [ b ] [ join ]
  []presJoins join is-join = SetQuot.elimProp  x  isOfHLevel⁺≃ₗ 0 (isPropValued≤ [ join ] x)) is-join

  []presHasJoin : Join P.isProset a b  Join isProset≤ [ a ] [ b ]
  []presHasJoin join = [ join .fst ] , []presJoins (join .fst) (join .snd)

  hasBinJoins : (∀ a b  Join P.isProset a b)  isJoinSemipseudolattice ReflectionPoset
  hasBinJoins bin-joins = SetQuot.elimProp2 (JoinUnique isPoset≤) λ a b  []presHasJoin (bin-joins a b)