{-# OPTIONS --without-K --safe #-}

open import Categories.Category using (module Commutation) renaming (Category to Setoid-Category)
open import Categories.Category.Monoidal using (Monoidal)

module Categories.Enriched.Functor {o  e} {V : Setoid-Category o  e}
                                   (M : Monoidal V) where

open import Level

open import Categories.Enriched.Category M
open import Categories.Enriched.Category.Underlying M
open import Categories.Functor using () renaming (Functor to Setoid-Functor)
open import Categories.Morphism.Reasoning V
open import Categories.Category.Monoidal.Reasoning M using (⊗-distrib-over-∘)

open Setoid-Category V renaming (Obj to ObjV; id to idV)
open Commutation V
open HomReasoning
open Monoidal M

record Functor {c d} (C : Category c) (D : Category d) : Set (  e  c  d) where
  eta-equality
  private
    module C = Category C
    module D = Category D

  field
    map₀ : C.Obj  D.Obj
    map₁ :  {X Y}  C [ X , Y ]  D [ map₀ X , map₀ Y ]

    identity     :  {X}  map₁  C.id  D.id {map₀ X}
    homomorphism :  {X Y Z} 
      [ C [ Y , Z ] ⊗₀ C [ X , Y ]  D [ map₀ X , map₀ Z ] ]⟨
        C.⊚           ⇒⟨ C [ X , Z ]                  map₁
       map₁ ⊗₁ map₁  ⇒⟨ D [ _ , _ ] ⊗₀ D [ _ , _ ]   D.⊚
      

    -- We don't need an analogue of F-resp-≈ because |hom A B| is not
    -- a hom-Setoid but a hom-object (in V) and the functorial action
    -- is not a Setoid-map but a V-morphism.  Whether V-objects have a
    -- notion of equality, and whether such equalities are preserved
    -- by V-morphisms, depends entirely on V.

  -- Shorthands for the functorial actions that work well as
  -- post-projections.

   = map₀
   = map₁

Endofunctor :  {c}  Category c  Set (  e  c)
Endofunctor C = Functor C C

id :  {c} {C : Category c}  Endofunctor C
id {_} {C} = record
  { map₀         = λ X  X
  ; map₁         = idV
  ; identity     = identityˡ
  ; homomorphism = id-comm-sym  ∘-resp-≈ʳ ( ⊗.identity)
  }
  where
  open Category C

infixr 9 _∘F_

_∘F_ :  {c d e} {C : Category c} {D : Category d} {E : Category e} 
       Functor D E  Functor C D  Functor C E
_∘F_ {_} {_} {_} {C} {D} {E} G F = record
  { map₀     = λ X  G.₀ (F.₀ X)
  ; map₁     = G.₁  F.₁
  ; identity = begin
      (G.₁  F.₁)  C.id   ≈⟨ pullʳ F.identity 
      G.₁  D.id           ≈⟨ G.identity 
      E.id                 
  ; homomorphism = begin
      (G.₁  F.₁)  C.⊚                  ≈⟨ pullʳ F.homomorphism 
      G.₁  (D.⊚  F.₁ ⊗₁ F.₁)           ≈⟨ pullˡ G.homomorphism 
      (E.⊚  G.₁ ⊗₁ G.₁)  F.₁ ⊗₁ F.₁    ≈˘⟨ pushʳ ⊗-distrib-over-∘ 
      E.⊚  (G.₁  F.₁) ⊗₁ (G.₁  F.₁)   
  }
  where
    module C = Category C
    module D = Category D
    module E = Category E
    module F = Functor F
    module G = Functor G

-- A V-enriched functor induces an ordinary functor on the underlying
-- categories.

module _ {c d} {C : Category c} {D : Category d} where

  UnderlyingFunctor : Functor C D  Setoid-Functor (Underlying C) (Underlying D)
  UnderlyingFunctor F = record
    { F₀           = F.₀
    ; F₁           = F.₁ ∘_
    ; identity     = F.identity
    ; homomorphism = λ {_} {_} {_} {f} {g}  begin
        F.₁  C.⊚  g ⊗₁ f  λ⇐             ≈⟨ pullˡ F.homomorphism 
        (D.⊚  F.₁ ⊗₁ F.₁)  g ⊗₁ f  λ⇐    ≈˘⟨ pushʳ (pushˡ ⊗-distrib-over-∘) 
        D.⊚  (F.₁  g) ⊗₁ (F.₁  f)  λ⇐   
    ; F-resp-≈     = ∘-resp-≈ʳ
    }
    where
      module C = Category C
      module D = Category D
      module F = Functor F

      λ⇐ = unitorˡ.to

  module UnderlyingFunctor F = Setoid-Functor (UnderlyingFunctor F)