{-# OPTIONS --safe #-}

module Multiset.Categories.Coalgebra where

open import Multiset.Prelude

open import Cubical.Foundations.HLevels
open import Cubical.Categories.Category
open import Cubical.Categories.Functor
open import Cubical.Categories.Limits.Terminal
open import Cubical.Reflection.RecordEquiv

private
  variable ℓC ℓC' : Level

module _ {C : Category ℓC ℓC'} (F : Functor C C) where

  open Category

  open Functor F
    renaming (F-ob to F₀_ ; F-hom to F₁_)

  IsCoalgebra : ob C  Type ℓC'
  IsCoalgebra x = C [ x , F₀ x ]
  
  record Coalgebra : Type (ℓ-max ℓC ℓC') where
    constructor coalgebra
    field
      {carrier} : ob C
      str : IsCoalgebra carrier

  open Coalgebra

  IsCoalgebraHom : (α β : Coalgebra)  C [ carrier α , carrier β ]  Type ℓC'
  IsCoalgebraHom α β f = f ⋆⟨ C  β .str  α .str ⋆⟨ C  F₁ f

  isPropIsCoalgebraHom : {α β : Coalgebra} (f : C [ carrier α , carrier β ])  isProp (IsCoalgebraHom α β f)
  isPropIsCoalgebraHom f = C .isSetHom _ _

  record CoalgebraHom (α β : Coalgebra) : Type ℓC' where
    constructor coalgebraHom
    field
      carrierHom : C [ carrier α , carrier β ]
      strHom : IsCoalgebraHom α β carrierHom
  open CoalgebraHom

  unquoteDecl CoalgebraHomIsoΣ = declareRecordIsoΣ CoalgebraHomIsoΣ (quote CoalgebraHom)

  isSetCoalgebraHom : {α β : Coalgebra}  isSet (CoalgebraHom α β)
  isSetCoalgebraHom = isOfHLevelRetractFromIso 2 CoalgebraHomIsoΣ (isSetΣSndProp (C .isSetHom) isPropIsCoalgebraHom)

  idCoalgebraHom : {α : Coalgebra}  CoalgebraHom α α
  idCoalgebraHom {α} .carrierHom = id C
  idCoalgebraHom {α} .strHom = goal where abstract
    goal : IsCoalgebraHom α α (id C)
    goal =
      id C ⋆⟨ C  α .str  ≡⟨ ⋆IdL C (α .str) 
      α .str              ≡⟨ sym (⋆IdR C _) 
      α .str ⋆⟨ C  id C  ≡⟨ cong  f  α .str ⋆⟨ C  f) (sym F-id) 
      F₁ (id C) ∘⟨ C  α .str 

  CoalgebraHom≡ : {α β : Coalgebra} {f g : CoalgebraHom α β}
     (f .carrierHom  g .carrierHom)
     f  g
  CoalgebraHom≡ p i .carrierHom = p i
  CoalgebraHom≡ {f = f} {g = g} p i .strHom = isProp→PathP  i  isPropIsCoalgebraHom (p i)) (f .strHom) (g .strHom) i

  Coalg⟨_⟩[_,_] = CoalgebraHom

  seqCoalgebraHom : {α β γ : Coalgebra}
     (f : CoalgebraHom α β)
     (g : CoalgebraHom β γ)
     CoalgebraHom α γ
  seqCoalgebraHom f g .carrierHom = f .carrierHom ⋆⟨ C  g .carrierHom
  seqCoalgebraHom {α} {β} {γ} (coalgebraHom f f-hom) (coalgebraHom g g-hom) .strHom = goal where abstract
    goal : IsCoalgebraHom α γ (f ⋆⟨ C  g)
    goal =
      (f ⋆⟨ C  g) ⋆⟨ C  γ .str        ≡⟨ ⋆Assoc C _ _ _ 
      f ⋆⟨ C  (g ⋆⟨ C  γ .str)        ≡⟨ lCatWhisker {C = C} _ _ _ g-hom 
      f ⋆⟨ C  (β .str ⋆⟨ C  F₁ g)     ≡⟨ sym (⋆Assoc C _ _ _) 
      (f ⋆⟨ C  β .str) ⋆⟨ C  F₁ g     ≡⟨ rCatWhisker {C = C} _ _ _ f-hom 
      (α .str ⋆⟨ C  F₁ f) ⋆⟨ C  F₁ g  ≡⟨ ⋆Assoc C _ _ _ 
      α .str ⋆⟨ C  (F₁ f ⋆⟨ C  F₁ g)  ≡⟨ lCatWhisker {C = C} _ _ _ (sym (F-seq f g)) 
      α .str ⋆⟨ C  F₁ (f ⋆⟨ C  g) 

  CoalgebrasCategory : Category (ℓ-max ℓC ℓC') ℓC'
  CoalgebrasCategory .ob = Coalgebra
  CoalgebrasCategory .Hom[_,_] = CoalgebraHom
  CoalgebrasCategory .id = idCoalgebraHom
  CoalgebrasCategory ._⋆_ = seqCoalgebraHom
  CoalgebrasCategory .⋆IdL _ = CoalgebraHom≡ (⋆IdL C _)
  CoalgebrasCategory .⋆IdR _ = CoalgebraHom≡ (⋆IdR C _)
  CoalgebrasCategory .⋆Assoc _ _ _ = CoalgebraHom≡ (⋆Assoc C _ _ _)
  CoalgebrasCategory .isSetHom = isSetCoalgebraHom

  isTerminalCoalgebra : Coalgebra  Type _
  isTerminalCoalgebra = isTerminal CoalgebrasCategory

  isPropIsTerminalCoalgebra : {ω : Coalgebra}  isProp (isTerminalCoalgebra ω)
  isPropIsTerminalCoalgebra {ω} = isPropIsTerminal CoalgebrasCategory ω

  TerminalCoalgebra : Type _
  TerminalCoalgebra = Terminal CoalgebrasCategory