{-# OPTIONS --without-K --safe #-}
module Categories.Category.Construction.F-Coalgebras where

open import Level

open import Categories.Category
open import Categories.Functor hiding (id)
open import Categories.Functor.Algebra
open import Categories.Functor.Coalgebra
open import Categories.Object.Initial
open import Categories.Object.Terminal
import Categories.Morphism.Reasoning as MR
import Categories.Morphism as Mor using (_≅_; Iso)
open import Categories.Category.Construction.F-Algebras
open import Categories.Functor.Duality

private
  variable
    o  e : Level
    C : Category o  e

F-Coalgebras : {C : Category o  e}  Endofunctor C  Category (  o) (e  ) e
F-Coalgebras {C = C} F = record
  { Obj       = F-Coalgebra F
  ; _⇒_       = F-Coalgebra-Morphism
  ; _≈_       = λ α₁ α₂  f α₁  f α₂
  ; _∘_       = λ α₁ α₂  record
    { f = f α₁  f α₂
    ; commutes = F-Algebra-Morphism.commutes (F-Coalgebra-Morphism⇒coF-Algebra-Morphism α₁
       coF-Algebras.∘
       F-Coalgebra-Morphism⇒coF-Algebra-Morphism α₂)
    }
  ; id        = record { f = id; commutes = F-Algebra-Morphism.commutes coF-Algebras.id }
  ; assoc     = assoc
  ; sym-assoc = sym-assoc
  ; identityˡ = identityˡ
  ; identityʳ = identityʳ
  ; identity² = identity²
  ; equiv     = record
    { refl  = refl
    ; sym   = sym
    ; trans = trans
    }
  ; ∘-resp-≈  = ∘-resp-≈
  }
  where
    open Category C
    open MR C
    open HomReasoning
    open Equiv
    open F-Coalgebra-Morphism
    module coF-Algebras = Category (Category.op (F-Algebras (Functor.op F)))

F-Coalgebras⇒coF-Algebras : {C : Category o  e}  (F : Endofunctor C)  Functor (F-Coalgebras F) (Category.op (F-Algebras (Functor.op F)))
F-Coalgebras⇒coF-Algebras {C = C} F = record
  { F₀           = F-Coalgebra⇒coF-Algebra
  ; F₁           = F-Coalgebra-Morphism⇒coF-Algebra-Morphism
  ; identity     = refl
  ; homomorphism = refl
  ; F-resp-≈     = λ x  x
  }
  where
    open Category C
    open MR C
    open HomReasoning
    open Equiv
    open F-Coalgebra-Morphism

private
  coIsTerminal⇒Initial :  {C : Category o  e} {F : Endofunctor C}
    {T : Category.Obj (F-Coalgebras F) } 
    IsTerminal (F-Coalgebras F) T 
    IsInitial (F-Algebras (Functor.op F)) (F-Coalgebra⇒coF-Algebra T)
  coIsTerminal⇒Initial {C = C} {F = F} {T = T} isTT = record
    { ! =
        F-Coalgebra-Morphism⇒coF-Algebra-Morphism ¡
    ; !-unique =
        λ  γ   Functor.F-resp-≈ (F-Coalgebras⇒coF-Algebras F)
        {f = ¡}
        {g = coF-Algebra-Morphism⇒F-Coalgebra-Morphism γ}
        (¡-unique (coF-Algebra-Morphism⇒F-Coalgebra-Morphism γ))
    }
    where
      open Category (F-Algebras (Functor.op F))
      open MR (F-Algebras (Functor.op F))
      open IsTerminal isTT renaming (! to ¡; !-unique to ¡-unique)
      open HomReasoning
      open Equiv

module CoLambek {C : Category o  e} {F : Endofunctor C} (T : Terminal (F-Coalgebras F)) where
  open Category C
  open Functor F using (F₀)
  open F-Coalgebra using (α)

  open Mor C
  open Terminal T

  private
    module F⊤ = F-Coalgebra 
    A = F⊤.A
    a : A  F₀ A
    a = F⊤.α

    coInitial : Initial (F-Algebras (Functor.op F))
    coInitial = record
                {  = F-Coalgebra⇒coF-Algebra 
                ; ⊥-is-initial = coIsTerminal⇒Initial ⊤-is-terminal
                }

    module coLambek = Lambek coInitial

  colambek : A  F₀ A
  colambek = record
    { from = to coLambek.lambek
    ; to = from coLambek.lambek
    ; iso = record
      { isoˡ = isoˡ (iso coLambek.lambek)
      ; isoʳ = isoʳ (iso coLambek.lambek)
      }
    }
    where
      open HomReasoning
      open Mor._≅_
      open Mor.Iso