\import Category
\import Function.Meta ($)
\import Logic
\import Paths.Meta
\import Relation.Equivalence
\import Set

\class Preorder \extends BaseSet, Precat (\lp,\lp) {
  | \infix 4 <= : E -> E -> \Prop
  | <=-refl {x : E} : x <= x
  | <=-transitive \alias \infixr 9 <=∘ {x y z : E} : x <= y -> y <= z -> x <= z

  | Ob => E
  | Hom => <=
  | id _ => <=-refl
  | o f g => g <=∘ f
  | id-left => prop-pi
  | id-right => prop-pi
  | o-assoc => prop-pi

  | \infix 4 >= : E -> E -> \Prop
  | >= x y => y <= x

  \lemma =_<= {x y : E} (p : x = y) : x <= y
    | idp => <=-refl

  \func op : Preorder E \cowith
    | <= x y => y <= x
    | <=-refl => <=-refl
    | <=-transitive p q => <=-transitive q p

  \func EquivRel : Equivalence E \cowith
    | ~ x y => \Sigma (x <= y) (y <= x)
    | ~-reflexive {x} => (<=-refl, <=-refl)
    | ~-symmetric {x} {y} x~y => (x~y.2, x~y.1)
    | ~-transitive {x} {y} {z} x~y y~z => (x~y.1 <=∘ y~z.1, y~z.2 <=∘ x~y.2)

  \func PreorderC => Quotient (EquivRel.~)

  \instance PosetC : Poset PreorderC
    | <= => <=C
    | <=-refl => <=C-reflexive
    | <=-transitive => <=C-transitive
    | <=-antisymmetric => <=C-antisymmetric
  \where {
    \func \infix 4 <=C (x y : PreorderC) : \Prop \elim x, y
      | in~ x, in~ y => x <= y
      | ~-equiv x x' x~x', in~ y => propExt (<=-transitive x~x'.2) (<=-transitive {_} {x} {x'} {y} x~x'.1)
      | in~ x, ~-equiv y y' y~y' => propExt (<=-transitive __ y~y'.1) (<=-transitive {_} {x} __ y~y'.2)

    \lemma <=C-reflexive {x : PreorderC} : x <=C x \elim x
      | in~ x => <=-refl

    \lemma <=C-transitive {x y z : PreorderC} (x<=y : x <=C y) (y<=z : y <=C z) : x <=C z \elim x, y, z
      | in~ x, in~ y, in~ z => <=-transitive x<=y y<=z

    \lemma <=C-antisymmetric {x y : PreorderC} (x<=y : x <=C y) (y<=x : y <=C x) : x = y \elim x, y
      | in~ x, in~ y => path (~-equiv x y (x<=y, y<=x))
  }

  \func IsMeet (x y m : E) => \Sigma (m <= x) (m <= y) (\Pi (m' : E) -> m' <= x -> m' <= y -> m' <= m)
}

\class Poset \extends Preorder, Cat (\lp,\lp) {
  | <=-antisymmetric {x y : E} : x <= y -> y <= x -> x = y
  | univalence => Cat.makeUnivalence \lam (e : Iso) => (<=-antisymmetric e.f e.hinv, prop-pi)

  \func op : Poset \cowith
    | Preorder => Preorder.op
    | <=-antisymmetric p q => <=-antisymmetric q p

  \lemma <=_= {x y : E} (p : x = y) : x <= y
    | idp => <=-refl
}

\instance ProductPoset (P Q : Poset) : Poset (\Sigma P Q)
  | Preorder => ProductPreorder P Q
  | <=-antisymmetric (p,q) (p',q') => ext (<=-antisymmetric p p', <=-antisymmetric q q')

\instance ProductPreorder (P Q : Preorder) : Preorder (\Sigma P Q)
  | <= (x,y) (x',y') => \Sigma (x <= x') (y <= y')
  | <=-refl => (<=-refl, <=-refl)
  | <=-transitive (p,q) (p',q') => (<=-transitive p p', <=-transitive q q')

\func subPoset {P : Poset} (S : P -> \Prop) : Poset (\Sigma (x : P) (S x)) \cowith
  | <= x y => x.1 <= y.1
  | <=-refl => <=-refl
  | <=-transitive => <=-transitive
  | <=-antisymmetric p q => ext (<=-antisymmetric p q)