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

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

module Categories.Bicategory.Instance.EnrichedCats
  {o  e} {V : Setoid-Category o  e} (M : Monoidal V) (v : Level) where

-- The 2-category of V-enriched categories

open import Data.Product as Prod using (_,_; proj₁)

open import Categories.Bicategory using (Bicategory)
open import Categories.Category.Construction.EnrichedFunctors M
import Categories.Morphism.Reasoning as MR
open import Categories.Enriched.Category M
open import Categories.Enriched.Category.Underlying M
open import Categories.Enriched.Functor M renaming (id to idF)
open import Categories.Enriched.NaturalTransformation M hiding (id)
import Categories.Enriched.NaturalTransformation.NaturalIsomorphism M as NI
open import Categories.Functor.Bifunctor using (Bifunctor)
open import Categories.Functor.Construction.Constant using (const)
open import Categories.NaturalTransformation.NaturalIsomorphism using (niHelper)

private
  module V = Setoid-Category V
  module UnderlyingReasoning {c} (C : Category c) where
    private
      CC = Underlying C
    open Underlying C using (_∘_; identityʳ; identityˡ; sym-assoc; module HomReasoning) public
    open HomReasoning public
    open MR CC using (id-comm-sym) public
  open NaturalTransformation
  open NI.NaturalIsomorphism

  -- Aliases used to shorten some proof expressions

  module UF = UnderlyingFunctor using (F₀; F₁; homomorphism; identity)
  infixr 14 _$₀_ _$₁_
  _$₀_ = UF.F₀
  _$₁_ = UF.F₁

-- The bicategory of V-enriched categories, functors and natural
-- transformations.
--
-- Note that all the equational reasoning happens in the underlying
-- (ordinary) categories!

-- below, a lot of specification of implicits make things typecheck faster.
EnrichedCats : Bicategory (  e  v) (  e  v) (e  v) (o    e  suc v)
EnrichedCats = record
  { enriched = record
    { Obj = Category v
    ; hom = EnrichedFunctors
    ; id  = const idF
    ;    = 
    ; ⊚-assoc =  λ {_ _ C D} 
      let module C = Underlying C
          module D = Underlying D
          open UnderlyingReasoning D
      in niHelper record
        { η       = λ { ((F , G) , H)  from (NI.associator {F = F} {G} {H}) }
        ; η⁻¹     = λ { ((F , G) , H)  to   (NI.associator {F = F} {G} {H}) }
        ; commute = λ { {(_ , G₁) , H₁} {(F₂ , G₂) , _} ((α , β) , γ) {X} 
          -- short hands for terms that never change
          let α′ = α [ G₁ $₀ H₁ $₀ X ]
              β′ = β [ H₁ $₀ X ]
          in begin
            D.id  (F₂ ∘F G₂) $₁ γ [ X ]  F₂ $₁ β′  α′ ≈⟨ identityˡ  sym-assoc 
            ((F₂ ∘F G₂) $₁ γ [ X ]  F₂ $₁ β′)  α′      ≈⟨ V.assoc ⟩∘⟨refl ⟩∘⟨refl 
            (F₂ $₁ G₂ $₁ γ [ X ]  F₂ $₁ β′)  α′        ≈˘⟨ UF.homomorphism F₂ ⟩∘⟨refl 
            F₂ $₁ (G₂ $₁ γ [ X ] C.∘ β′)  α′            ≈˘⟨ identityʳ 
            (F₂ $₁ (G₂ $₁ γ [ X ] C.∘ β′)  α′)  D.id    }
        ; iso = λ{ ((F , G) , H)  iso (NI.associator {F = F} {G} {H}) }
        }
    ; unitˡ =  λ {A B} 
      let module A = Underlying A
          module B = Underlying B
          open UnderlyingReasoning B
      in niHelper record
        { η       = λ {(_ , F)  from (NI.unitorˡ {C = A} {B} {F})}
        ; η⁻¹     = λ {(lift _ , F)  to (NI.unitorˡ {C = A} {B} {F})}
        ; commute = λ { {_ , F} {_ , G} (_ , α) {X} 
          begin
            B.id  (V.id V.∘ α [ X ])  B.id   ≈⟨ identityˡ 
            (V.id V.∘ α [ X ])  B.id          ≈⟨ V.identityˡ ⟩∘⟨refl 
            α [ X ]  B.id                      }
        ; iso = λ {(_ , F)  iso (NI.unitorˡ {C = A} {B} {F})}
        }
    ; unitʳ = λ {A B} 
      let module A = Underlying A using (id)
          module B = Underlying B
          open UnderlyingReasoning B
      in niHelper record
        { η =  λ {(F , lift _)  from (NI.unitorʳ {C = A} {B} {F}) }
        ; commute =  λ{ {_} {G , _} (α , _) {X} 
            begin
              B.id  G $₁ A.id  α [ X ]  ≈⟨ identityˡ 
              G $₁ A.id  α [ X ]         ≈⟨ UF.identity G ⟩∘⟨refl 
              B.id  α [ X ]              ≈⟨ id-comm-sym 
              α [ X ]  B.id               }
        ; η⁻¹  = λ { (F , lift _)  to (NI.unitorʳ {C = A} {B} {F}) }
        ; iso  = λ { (F , lift _)  iso (NI.unitorʳ {C = A} {B} {F}) }
        }
    }
  ; triangle = λ {_ _ C f g X}  UnderlyingReasoning.identityʳ C
  ; pentagon = λ {_ B _ D E _ G H I} 
    let module B  = Category B using (id)
        module D  = Category D using (id)
        module E  = Category E using (id)
        open UnderlyingReasoning E
    in begin
      (I $₁ D.id  E.id)  E.id  (I ∘F H ∘F G) $₁ B.id  E.id ≈⟨ identityʳ ⟩∘⟨ identityˡ 
      I $₁ D.id  (I ∘F H ∘F G) $₁ B.id  E.id                 ≈⟨ refl⟩∘⟨ identityʳ 
      I $₁ D.id  (I ∘F H ∘F G) $₁ B.id                        ≈⟨ UF.identity I ⟩∘⟨ UF.identity (I ∘F H ∘F G) 
      E.id  E.id
    
  }