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

open import Categories.Category.Core

module Categories.Morphism.Extremal.Properties {o  e} (𝒞 : Category o  e) where

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

open import Categories.Diagram.Equalizer 𝒞
open import Categories.Diagram.Coequalizer 𝒞

open import Categories.Morphism 𝒞
open import Categories.Morphism.Extremal 𝒞
open import Categories.Morphism.Properties 𝒞
open import Categories.Morphism.Reasoning 𝒞
open import Categories.Morphism.Regular 𝒞

open Category 𝒞
open HomReasoning

private
  variable
    A B : Obj
    f g : A  B

--------------------------------------------------------------------------------
-- Extremal Epimorphisms

RegularEpi⇒IsExtremalEpi :  {A B} {f : A  B} (e : RegularEpi f)  IsExtremalEpi (RegularEpi⇒Epi e)
RegularEpi⇒IsExtremalEpi {A = A} {B = B} {f = f} regular {X = X} {i = i} {g = k} i-mono f≈i∘k =
  record
    { inv = i⁻¹
    ; iso = record
      { isoˡ = isoˡ
      ; isoʳ = isoʳ
      }
    }
  where
    open RegularEpi regular renaming (g to r; h to s)
    open IsCoequalizer coequalizer

    i⁻¹ : B  X
    i⁻¹ = coequalize $ i-mono (k  s) (k  r) $ begin
        i  k  s ≈⟨ pullˡ ( f≈i∘k) 
        f  s     ≈⟨ equality 
        f  r     ≈⟨ pushˡ f≈i∘k 
        i  k  r 

    isoʳ : i  i⁻¹  id
    isoʳ = RegularEpi⇒Epi regular (i  i⁻¹) id $ begin
      (i  i⁻¹)  f ≈⟨ pullʳ ( universal) 
      i  k         ≈˘⟨ f≈i∘k 
      f             ≈˘⟨ identityˡ 
      id  f        

    isoˡ : i⁻¹  i  id
    isoˡ = i-mono (i⁻¹  i) id $ begin
      i  i⁻¹  i ≈⟨ cancelˡ isoʳ 
      i           ≈˘⟨ identityʳ 
      i  id      

RegularEpi⇒ExtremalEpi : (e : RegularEpi f)  ExtremalEpi f
RegularEpi⇒ExtremalEpi e = record
  { epi = RegularEpi⇒Epi e
  ; extremal = RegularEpi⇒IsExtremalEpi e
  }

ExtremalEpi-∘₂ : ExtremalEpi (f  g)  ExtremalEpi f
ExtremalEpi-∘₂ fg-extremal = record
  { epi = Epi-∘₂ epi
  ; extremal = λ i-mono eq  extremal i-mono (pushˡ eq)
  }
  where
    open ExtremalEpi fg-extremal

ExtremalEpi-∘ :  {A B C} {f : B  C} {g : A  B}  ExtremalEpi f  RegularEpi g  ExtremalEpi (f  g)
ExtremalEpi-∘ {A = A} {B = B} {C = C} {f = f} {g = g} f-extremal g-regular = record
  { epi = fg-epi
  ; extremal = fg-extremal
  }
  where
    module f-extremal = ExtremalEpi f-extremal
    module g-regular = RegularEpi g-regular
    open IsCoequalizer g-regular.coequalizer

    g-epi : Epi g
    g-epi = RegularEpi⇒Epi g-regular

    fg-epi : Epi (f  g)
    fg-epi = Epi-∘ f-extremal.epi g-epi

    fg-extremal : IsExtremalEpi fg-epi
    fg-extremal {X = X} {i = i} {g = h} i-mono f∘g≈i∘h =
      f-extremal.extremal i-mono $ g-epi _ _ $ begin
        f  g       ≈⟨ f∘g≈i∘h 
        i  h       ≈⟨ pushʳ universal 
        (i  k)  g 
      where
        k : B  X
        k = coequalize $ i-mono _ _ $ begin
          i  h  g-regular.h ≈⟨ extendʳ ( f∘g≈i∘h) 
          f  g  g-regular.h ≈⟨ refl⟩∘⟨ equality 
          f  g  g-regular.g ≈⟨ extendʳ f∘g≈i∘h 
          i  h  g-regular.g 

ExtremalEpi+Mono⇒IsIso : ExtremalEpi f  Mono f  IsIso f
ExtremalEpi+Mono⇒IsIso {f = f} f-extremal f-mono = extremal f-mono ( identityʳ)
  where
    open ExtremalEpi f-extremal

--------------------------------------------------------------------------------
-- Extremal Monomorphisms

RegularMono⇒IsExtremalMono :  {A B} {f : A  B} (m : RegularMono f)  IsExtremalMono (RegularMono⇒Mono m)
RegularMono⇒IsExtremalMono {A = A} {B = B} {f = f} regular {X = X} {g = k} {i = i} i-epi f≈k∘i =
  record
    { inv = i⁻¹
    ; iso = record
      { isoˡ = isoˡ
      ; isoʳ = isoʳ
      }
    }
    where
      open RegularMono regular renaming (g to r; h to s)
      open IsEqualizer equalizer

      i⁻¹ : X  A
      i⁻¹ = equalize $ i-epi (s  k) (r  k) $ begin
        (s  k)  i ≈⟨ pullʳ ( f≈k∘i) 
        s  f       ≈⟨ equality 
        r  f       ≈⟨ pushʳ f≈k∘i 
        (r  k)  i 

      isoˡ : i⁻¹  i  id
      isoˡ = RegularMono⇒Mono regular (i⁻¹  i) id $ begin
        f  i⁻¹  i ≈⟨ pullˡ ( universal) 
        k  i       ≈˘⟨ f≈k∘i 
        f           ≈˘⟨ identityʳ 
        f  id      

      isoʳ : i  i⁻¹  id
      isoʳ = i-epi (i  i⁻¹) id $ begin
        (i  i⁻¹)  i ≈⟨ cancelʳ isoˡ 
        i             ≈˘⟨ identityˡ 
        id  i        

RegularMono⇒ExtremalMono : RegularMono f  ExtremalMono f
RegularMono⇒ExtremalMono m = record
  { mono = RegularMono⇒Mono m
  ; extremal = RegularMono⇒IsExtremalMono m
  }

ExtremalMono-∘₂ : ExtremalMono (f  g)  ExtremalMono g
ExtremalMono-∘₂ fg-extremal = record
  { mono = Mono-∘₂ mono
  ; extremal = λ i-epi eq  extremal i-epi (pushʳ eq)
  }
  where
    open ExtremalMono fg-extremal

ExtremalMono-∘ :  {A B C} {f : B  C} {g : A  B}  RegularMono f  ExtremalMono g  ExtremalMono (f  g)
ExtremalMono-∘ {A = A} {B = B} {f = f} {g = g} f-regular g-extremal = record
  { mono = fg-mono
  ; extremal = fg-extremal
  }
  where
    module f-regular = RegularMono f-regular
    open IsEqualizer f-regular.equalizer
    module g-extremal = ExtremalMono g-extremal

    f-mono : Mono f
    f-mono = (RegularMono⇒Mono f-regular)

    fg-mono : Mono (f  g)
    fg-mono = Mono-∘ f-mono g-extremal.mono

    fg-extremal : IsExtremalMono fg-mono
    fg-extremal {X = X} {g = h} {i = e} e-epi f∘g≈h∘e =
      g-extremal.extremal e-epi $ f-mono _ _ $ begin
      f  g     ≈⟨ f∘g≈h∘e 
      h  e     ≈⟨ pushˡ universal 
      f  k  e 
      where
        k : X  B
        k = equalize $ e-epi _ _ $ begin
          (f-regular.h  h)  e ≈⟨ extendˡ ( f∘g≈h∘e) 
          (f-regular.h  f)  g ≈⟨ equality ⟩∘⟨refl 
          (f-regular.g  f)  g ≈⟨ extendˡ f∘g≈h∘e 
          (f-regular.g  h)  e 

ExtremalMono+Epi⇒IsIso : ExtremalMono f  Epi f  IsIso f
ExtremalMono+Epi⇒IsIso {f = f} f-extremal f-epi = extremal f-epi ( identityˡ)
  where
    open ExtremalMono f-extremal

--------------------------------------------------------------------------------
-- Extremal Morphisms in Balanced Categories
-- https://ncatlab.org/nlab/show/balanced+category

module _ (balanced :  {A B} {f : A  B}  Mono f  Epi f  IsIso f) where

  Mono+Epi⇒IsExtremalEpi : (e : Epi f)  IsExtremalEpi e
  Mono+Epi⇒IsExtremalEpi {f = f} f-epi {i = i} {g = g} i-mono f≈i∘g = balanced i-mono i-epi
    where
      i-epi : Epi i
      i-epi g₁ g₂ g₁∘i≈g₂∘i = f-epi g₁ g₂ $ begin
        g₁  f       ≈⟨ pushʳ f≈i∘g 
        (g₁  i)  g ≈⟨ g₁∘i≈g₂∘i ⟩∘⟨refl 
        (g₂  i)  g ≈⟨ pullʳ ( f≈i∘g) 
        g₂  f 

  Mono+Epi⇒IsExtremalMono : (m : Mono f)  IsExtremalMono m
  Mono+Epi⇒IsExtremalMono {f = f} f-mono {g = g} {i = i} i-epi f≈g∘i = balanced i-mono i-epi
    where
      i-mono : Mono i
      i-mono g₁ g₂ i∘g₁≈i∘g₂ = f-mono g₁ g₂ $ begin
        f  g₁     ≈⟨ pushˡ f≈g∘i 
        g  i  g₁ ≈⟨ refl⟩∘⟨ i∘g₁≈i∘g₂ 
        g  i  g₂ ≈⟨ pullˡ ( f≈g∘i) 
        f  g₂