{-# OPTIONS --without-K --safe #-}
module Cats.Category.Constructions.Terminal where

open import Data.Product using (proj₁ ; proj₂)
open import Level

open import Cats.Category.Base

import Cats.Category.Constructions.Iso as Iso
import Cats.Category.Constructions.Unique as Unique


module Build {lo la l≈} (Cat : Category lo la l≈) where

  open Category Cat
  open Iso.Build Cat
  open Unique.Build Cat


  IsTerminal : Obj  Set (lo  la  l≈)
  IsTerminal  =  X  ∃! X 


  record HasTerminal : Set (lo  la  l≈) where
    field
       : Obj
      isTerminal : IsTerminal 


    ! :  X  X  
    ! X = ∃!′.arr (isTerminal X)


    !-unique :  {X} (f : X  )  ! X  f
    !-unique {X} f = ∃!′.unique (isTerminal X) _


    ⇒⊤-unique :  {X} (f g : X  )  f  g
    ⇒⊤-unique f g = ≈.trans (≈.sym (!-unique f)) (!-unique g)


    ⊤-unique :  {X}  IsTerminal X  X  
    ⊤-unique {X} term = record
      { forth = ! X
      ; back = term  .∃!′.arr
      ; back-forth = ≈.trans (≈.sym (term X .∃!′.unique _)) (term X .∃!′.unique _)
      ; forth-back = ⇒⊤-unique _ _
      }


  terminal-unique :  {X Y}  IsTerminal X  IsTerminal Y  X  Y
  terminal-unique X-term Y-term
    = HasTerminal.⊤-unique (record { isTerminal = Y-term }) X-term


open Build public using (HasTerminal)

private
  open module Build′ {lo la l≈} {C : Category lo la l≈}
    = Build C public using (IsTerminal ; terminal-unique)