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

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

-- Tensor products of enriched functors.

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

open import Data.Product using (_,_)

import Categories.Enriched.Category as Enriched
open Enriched using () renaming (Category to EnrichedCat)
open import Categories.Enriched.Category M using (_[_,_])
open import Categories.Enriched.Functor as EnrichedFunctor renaming (Functor to EnrichedFunctor)

open Setoid-Category V
open Commutation V
open Monoidal M
open HasInterchange I using (module swapInner) renaming (natural to interchange-natural)
open import Categories.Category.Monoidal.Reasoning M
open import Categories.Category.Monoidal.Utilities M
open import Categories.Enriched.Category.TensorProduct I using (_⊠_)
open import Categories.Morphism.Reasoning V
open Shorthands

private
  i⇒ = swapInner.from

module _ {a b c d}
        {𝒜 : EnrichedCat M a} { : EnrichedCat M b}
        {𝒞 : EnrichedCat M c} {𝒟 : EnrichedCat M d}
        where

  infixr 7 _⊠F_

  private
    module 𝒜 = EnrichedCat 𝒜
    module  = EnrichedCat 
    module 𝒞 = EnrichedCat 𝒞
    module 𝒟 = EnrichedCat 𝒟

  _⊠F_ : (F : EnrichedFunctor M 𝒜 𝒞) (G : EnrichedFunctor M  𝒟) 
         EnrichedFunctor M (𝒜  ) (𝒞  𝒟)
  F ⊠F G = record
    { map₀ = λ (A , B)  F.₀ A , G.₀ B
    ; map₁ = F.₁ ⊗₁ G.₁
    ; identity = identity
    ; homomorphism = homomorphism
    }
    where
    module F = EnrichedFunctor.Functor F
    module G = EnrichedFunctor.Functor G
    module 𝒜⊠ℬ = EnrichedCat (𝒜  )
    module 𝒞⊠𝒟 = EnrichedCat (𝒞  𝒟)

    variable
      A B C : 𝒜.Obj
      X Y Z : ℬ.Obj

    abstract
      identity : (F.₁ ⊗₁ G.₁)  𝒜⊠ℬ.id {A , X}  𝒞⊠𝒟.id
      identity = begin
        (F.₁ ⊗₁ G.₁)  (𝒜.id ⊗₁ ℬ.id)  λ⇐    ≈⟨ pullˡ ( ⊗.homomorphism) 
        ((F.₁  𝒜.id) ⊗₁ (G.₁  ℬ.id))  λ⇐   ≈⟨ F.identity ⟩⊗⟨ G.identity ⟩∘⟨refl 
        (𝒞.id ⊗₁ 𝒟.id)  λ⇐                   

      homomorphism :
        [ (𝒜 [ B , C ] ⊗₀  [ Y , Z ]) ⊗₀ (𝒜 [ A , B ] ⊗₀  [ X , Y ]) 
          𝒞 [ F.₀ A , F.₀ C ] ⊗₀ 𝒟 [ G.₀ X , G.₀ Z ] ]⟨
            𝒜⊠ℬ.⊚         ⇒⟨ 𝒜 [ A , C ] ⊗₀  [ X , Z ] 
            F.₁ ⊗₁ G.₁
           (F.₁ ⊗₁ G.₁) ⊗₁ (F.₁ ⊗₁ G.₁)
                            ⇒⟨ (𝒞 [ F.₀ B , F.₀ C ] ⊗₀ 𝒟 [ G.₀ Y , G.₀ Z ]) ⊗₀
                                (𝒞 [ F.₀ A , F.₀ B ] ⊗₀ 𝒟 [ G.₀ X , G.₀ Y ]) 
            𝒞⊠𝒟.⊚
          
      homomorphism = let F⊗G-homo = F.homomorphism ⟩⊗⟨ G.homomorphism in begin
        (F.₁ ⊗₁ G.₁)  (𝒜.⊚ ⊗₁ ℬ.⊚)  i⇒                      ≈⟨ pullˡ ( ⊗.homomorphism) 
        ((F.₁  𝒜.⊚) ⊗₁ (G.₁  ℬ.⊚))  i⇒                     ≈⟨ F⊗G-homo ⟩∘⟨refl 
        ((𝒞.⊚  (F.₁ ⊗₁ F.₁)) ⊗₁ (𝒟.⊚  (G.₁ ⊗₁ G.₁)))  i⇒   ≈⟨ pushˡ ⊗.homomorphism 
        (𝒞.⊚ ⊗₁ 𝒟.⊚)  (((F.₁ ⊗₁ F.₁) ⊗₁ (G.₁ ⊗₁ G.₁))  i⇒)  ≈⟨ pushʳ ( interchange-natural) 
        𝒞⊠𝒟.⊚  ((F.₁ ⊗₁ G.₁) ⊗₁ (F.₁ ⊗₁ G.₁))