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

module Categories.Category.Extensive where

-- https://ncatlab.org/nlab/show/extensive+category

open import Level
open import Function using (_$_)

open import Categories.Category.Core using (Category)
open import Categories.Diagram.Pullback using (Pullback; IsPullback; up-to-iso)
open import Categories.Diagram.Pullback.Properties using (module IsoPb)
open import Categories.Category.Cocartesian using (Cocartesian)
open import Categories.Object.Coproduct using (IsCoproduct)
open import Categories.Morphism
import Categories.Morphism.Reasoning as MR

record Extensive {o  e : Level} (𝒞 : Category o  e) : Set (suc (o    e)) where
  open Category 𝒞
  open Pullback using (p₁)

  field
    cocartesian : Cocartesian 𝒞

  module CC = Cocartesian cocartesian
  open CC using (_+_; i₁; i₂; ¡)

  field
    pullback₁ : {A B C : Obj} (f : A  B + C)  Pullback 𝒞 f i₁
    pullback₂ : {A B C : Obj} (f : A  B + C)  Pullback 𝒞 f i₂
    pullback-of-cp-is-cp : {A B C : Obj} (f : A  B + C)  IsCoproduct 𝒞 (p₁ (pullback₁ f)) (p₁ (pullback₂ f))
    
    pullback₁-is-mono :  {A B : Obj}  Mono 𝒞 (i₁ {A = A}{B = B})
    pullback₂-is-mono :  {A B : Obj}  Mono 𝒞 (i₂ {A = A}{B = B})

    disjoint :  {A B : Obj}  IsPullback 𝒞 ¡ ¡ (i₁ {A = A}{B = B}) i₂

  -- a version with non-canonical pullbacks
  module _ {A B C : Obj} {f : A  B + C} (pb₁ : Pullback 𝒞 f i₁) (pb₂ : Pullback 𝒞 f i₂) where
      private 
        open IsCoproduct (pullback-of-cp-is-cp f)
        open HomReasoning; open MR 𝒞
      
        open IsoPb 𝒞 (pullback₁ f) pb₁ renaming (P₀⇒P₁ to pb₁-to-can; p₁-≈ to p₁-≈₁)
        open IsoPb 𝒞 (pullback₂ f) pb₂ renaming (P₀⇒P₁ to pb₂-to-can; p₁-≈ to p₁-≈₂)

        can-to-pb₁ = _≅_.from $ up-to-iso 𝒞 pb₁ (pullback₁ f)
        can-to-pb₂ = _≅_.from $ up-to-iso 𝒞 pb₂ (pullback₂ f)

      pullback-of-cp-is-cp' : IsCoproduct 𝒞 (p₁ pb₁) (p₁ pb₂)
      
      IsCoproduct.[_,_] pullback-of-cp-is-cp' g h  = [ g  pb₁-to-can , h  pb₂-to-can ]
      IsCoproduct.inject₁ pullback-of-cp-is-cp' {_}{g}{h}  = begin
         [ g  pb₁-to-can , h  pb₂-to-can ]  p₁ pb₁                               ≈˘⟨ refl⟩∘⟨ cancelʳ (Iso.isoˡ $ _≅_.iso $ up-to-iso 𝒞 pb₁ (pullback₁ f))  
         [ g  pb₁-to-can , h  pb₂-to-can ]  (p₁ pb₁  pb₁-to-can)  can-to-pb₁    ≈⟨ refl⟩∘⟨ p₁-≈₁ ⟩∘⟨refl 
         [ g  pb₁-to-can , h  pb₂-to-can ]  p₁ (pullback₁ f)  can-to-pb₁         ≈⟨ pullˡ inject₁ 
         (g  pb₁-to-can)  can-to-pb₁                                               ≈⟨ cancelʳ (Iso.isoˡ $ _≅_.iso $ up-to-iso 𝒞 pb₁ (pullback₁ f))  
         g                                                                           

      IsCoproduct.inject₂ pullback-of-cp-is-cp' {_}{g}{h} = begin
         [ g  pb₁-to-can , h  pb₂-to-can ]  p₁ pb₂                               ≈˘⟨ refl⟩∘⟨ cancelʳ (Iso.isoˡ $ _≅_.iso $ up-to-iso 𝒞 pb₂ (pullback₂ f))  
         [ g  pb₁-to-can , h  pb₂-to-can ]  (p₁ pb₂  pb₂-to-can)  can-to-pb₂    ≈⟨ refl⟩∘⟨ p₁-≈₂ ⟩∘⟨refl 
         [ g  pb₁-to-can , h  pb₂-to-can ]  p₁ (pullback₂ f)  can-to-pb₂         ≈⟨ pullˡ inject₂ 
         (h  pb₂-to-can)  can-to-pb₂                                               ≈⟨ cancelʳ (Iso.isoˡ $ _≅_.iso $ up-to-iso 𝒞 pb₂ (pullback₂ f))  
         h                                                                           
        
      IsCoproduct.unique pullback-of-cp-is-cp'   {_}{u}{g}{h}  u∘p₁pb₁≈g u∘p₁pb₂≈h  = unique
        (begin
                     u  p₁ (pullback₁ f)            ≈˘⟨ pullʳ p₁-≈₁  
                     (u  p₁ pb₁)  pb₁-to-can       ≈⟨ u∘p₁pb₁≈g ⟩∘⟨refl 
                     g  pb₁-to-can                  )
        (begin
                     u  p₁ (pullback₂ f)           ≈˘⟨ pullʳ p₁-≈₂  
                     (u  p₁ pb₂)  pb₂-to-can       ≈⟨ u∘p₁pb₂≈h ⟩∘⟨refl 
                     h  pb₂-to-can                  )