open import Level
open import Categories.Category.Core
open import Categories.Object.NaturalNumbers.Parametrized
open import Categories.Category.Distributive
open import Categories.Object.Terminal
open import Monad.Instance.Delay
open import Monad.Instance.Delay.Quotient

import Categories.Morphism as M
import Categories.Morphism.Reasoning as MR
import Categories.Morphism.Properties as MP

module Monad.Instance.Delay.Quotient.KTheorem.Condition3-1 {o  e} {C : Category o  e}
    (distributive : Distributive C) (DM : DelayM (Distributive.cocartesian distributive))
    (PNNO : ParametrizedNNO C (Distributive.cartesian distributive))
    (DQ : DelayQ distributive DM PNNO) where
    
  open import Categories.Diagram.Coequalizer C
  open Category C
  open import Category.Distributive.Helper distributive renaming (η to η-prod)
  open import Monad.Instance.K distributive
  open import Monad.Strong.Helper cartesian
  open Bundles 
  open import Algebra.Elgot cocartesian
  open import Algebra.Search cocartesian DM
  open import Algebra.Search.Properties cocartesian DM

  open import Monad.Instance.Delay.Quotient.KTheorem.Conditions distributive DM PNNO DQ
  open import Monad.Instance.Delay.Strong distributive DM
  open Equiv
  open HomReasoning
  open M C
  open MR C
  open MP C
  open DelayM DM
  open Coit
  open D-Monad
  open D-Kleisli
  -- open D-Strong
  open τ-mod
  open DelayQ DQ
  private
    module PNNO = ParametrizedNNO PNNO
  open PNNO using (s; z; N)
  open import Monad.Instance.Delay.Iota distributive DM PNNO

  open Later∘Extend

  -- preparatory definitions and facts
  module _ {X : Obj} where
    open import Object.NaturalNumbers.Parametrized cartesian (PNNO⇒NNO C cartesian PNNO)

    w : D₀ X × D₀   D₀ X + D₀ X × D₀ 
    w = [ i₁  π₁ , i₂  (earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out)

    w-now : w  (id ×₁ now)  i₁  π₁
    w-now = begin 
      ([ i₁  π₁ , i₂  (earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out))  (id ×₁ now) ≈⟨ pullʳ (pullʳ (×₁∘×₁  ×₁-cong₂ identity² unitlaw))  
      [ i₁  π₁ , i₂  (earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₁)                  ≈⟨ refl⟩∘⟨ distributeˡ⁻¹-i₁  
      [ i₁  π₁ , i₂  (earlier ×₁ id) ]  i₁                                          ≈⟨ inject₁  
      i₁  π₁                                                                          

    w-later : w  (id ×₁ later)  i₂  (earlier ×₁ id)
    w-later = begin 
      ([ i₁  π₁ , i₂  (earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out))  (id ×₁ later) ≈⟨ pullʳ (pullʳ (×₁∘×₁  ×₁-cong₂ identity² laterlaw))  
      [ i₁  π₁ , i₂  (earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₂)                    ≈⟨ refl⟩∘⟨ distributeˡ⁻¹-i₂  
      [ i₁  π₁ , i₂  (earlier ×₁ id) ]  i₂                                            ≈⟨ inject₂  
      i₂  (earlier ×₁ id)                                                               


    D-jointly-epic-product :  {X Y Z} {f g : D₀ Z × D₀ X  Y}  (f  (now ×₁ now)  g  (now ×₁ now))  (f  (later ×₁ now)  g  (later ×₁ now))  (f  (now ×₁ later)  g  (now ×₁ later))  (f  (later ×₁ later)  g  (later ×₁ later))  f  g
    D-jointly-epic-product {X} {Y} {Z} {f} {g} now-now later-now now-later later-later = begin 
      f                                   ≈⟨ introʳ (⟨⟩-unique (id-comm  ∘-resp-≈ˡ (sym out⁻¹∘out)) (id-comm  ∘-resp-≈ˡ (sym out⁻¹∘out)))  
      f  (out⁻¹  out ×₁ out⁻¹  out)    ≈˘⟨ refl⟩∘⟨ ×₁∘×₁  
      f  (out⁻¹ ×₁ out⁻¹)  (out ×₁ out) ≈⟨ extendʳ (distribution  helper  sym distribution)  
      g  (out⁻¹ ×₁ out⁻¹)  (out ×₁ out) ≈⟨ refl⟩∘⟨ ×₁∘×₁  
      g  (out⁻¹  out ×₁ out⁻¹  out)    ≈⟨ elimʳ (⟨⟩-unique (id-comm  ∘-resp-≈ˡ (sym out⁻¹∘out)) (id-comm  ∘-resp-≈ˡ (sym out⁻¹∘out)))  
      g                                   
      where
      distribution :  {h : D₀ Z × D₀ X  Y}  h  (out⁻¹ ×₁ out⁻¹)  [ [ h  (now ×₁ now) , h  (later ×₁ now) ] , [ h  (now ×₁ later) , h  (later ×₁ later) ] ]  (distributeʳ⁻¹ +₁ distributeʳ⁻¹)  distributeˡ⁻¹
      distribution {h} = Iso⇒Epi (IsIso.iso isIsoˡ) (h  (out⁻¹ ×₁ out⁻¹)) ([ [ h  (now ×₁ now) , h  (later ×₁ now) ] , [ h  (now ×₁ later) , h  (later ×₁ later) ] ]  (distributeʳ⁻¹ +₁ distributeʳ⁻¹)  distributeˡ⁻¹) (begin 
        (h  (out⁻¹ ×₁ out⁻¹))  distributeˡ                                                                                                                             ≈⟨ ∘[]  []-cong₂ (pullʳ (×₁∘×₁  ×₁-cong₂ identityʳ refl)) (pullʳ (×₁∘×₁  ×₁-cong₂ identityʳ refl))  
        [ h  (out⁻¹ ×₁ now) , h  (out⁻¹ ×₁ later) ]                                                                                                                    ≈⟨ []-cong₂ distribution-helper₁ distribution-helper₂  
        [ [ h  (now ×₁ now) , h  (later ×₁ now) ]  distributeʳ⁻¹ , [ h  (now ×₁ later) , h  (later ×₁ later) ]  distributeʳ⁻¹ ]                                    ≈˘⟨ []∘+₁  
        [ [ h  (now ×₁ now) , h  (later ×₁ now) ] , [ h  (now ×₁ later) , h  (later ×₁ later) ] ]  (distributeʳ⁻¹ +₁ distributeʳ⁻¹)                                 ≈˘⟨ pullʳ (cancelʳ (IsIso.isoˡ isIsoˡ))  
        ([ [ h  (now ×₁ now) , h  (later ×₁ now) ] , [ h  (now ×₁ later) , h  (later ×₁ later) ] ]  (distributeʳ⁻¹ +₁ distributeʳ⁻¹)  distributeˡ⁻¹)  distributeˡ )
        where
        distribution-helper₁ : h  (out⁻¹ ×₁ now)  [ h  (now ×₁ now) , h  (later ×₁ now) ]  distributeʳ⁻¹
        distribution-helper₁ = Iso⇒Epi (IsIso.iso isIsoʳ) (h  (out⁻¹ ×₁ now)) ([ h  (now ×₁ now) , h  (later ×₁ now) ]  distributeʳ⁻¹) (begin 
          (h  (out⁻¹ ×₁ now))  distributeʳ                                        ≈⟨ ∘[]  []-cong₂ (pullʳ (×₁∘×₁  ×₁-cong₂ refl identityʳ)) (pullʳ (×₁∘×₁  ×₁-cong₂ refl identityʳ))  
          [ h  (now ×₁ now) , h  (later ×₁ now) ]                                 ≈˘⟨ cancelʳ (IsIso.isoˡ isIsoʳ)  
          ([ h  (now ×₁ now) , h  (later ×₁ now) ]  distributeʳ⁻¹)  distributeʳ )
        distribution-helper₂ : h  (out⁻¹ ×₁ later)  [ h  (now ×₁ later) , h  (later ×₁ later) ]  distributeʳ⁻¹
        distribution-helper₂ = Iso⇒Epi (IsIso.iso isIsoʳ) (h  (out⁻¹ ×₁ later)) ([ h  (now ×₁ later) , h  (later ×₁ later) ]  distributeʳ⁻¹) (begin 
          (h  (out⁻¹ ×₁ later))  distributeʳ                                          ≈⟨ ∘[]  []-cong₂ (pullʳ (×₁∘×₁  ×₁-cong₂ refl identityʳ)) (pullʳ (×₁∘×₁  ×₁-cong₂ refl identityʳ))  
          [ h  (now ×₁ later) , h  (later ×₁ later) ]                                 ≈˘⟨ cancelʳ (IsIso.isoˡ isIsoʳ)  
          ([ h  (now ×₁ later) , h  (later ×₁ later) ]  distributeʳ⁻¹)  distributeʳ )
      helper : [ [ f  (now ×₁ now) , f  (later ×₁ now) ] , [ f  (now ×₁ later) , f  (later ×₁ later) ] ]  (distributeʳ⁻¹ +₁ distributeʳ⁻¹)  distributeˡ⁻¹  [ [ g  (now ×₁ now) , g  (later ×₁ now) ] , [ g  (now ×₁ later) , g  (later ×₁ later) ] ]  (distributeʳ⁻¹ +₁ distributeʳ⁻¹)  distributeˡ⁻¹
      helper = ∘-resp-≈ˡ ([]-cong₂ ([]-cong₂ now-now later-now) ([]-cong₂ now-later later-later))

    PNNO-jointly-epic :  {X Y} {f g : X × N  Y}  (f   id , z  !   g   id , z  ! )  (f  (id ×₁ s)  g  (id ×₁ s))  f  g
    PNNO-jointly-epic {X} {Y} {f} {g} IB IS = begin 
      f                                                           ≈⟨ introʳ (M._≅_.isoˡ nno-iso)  
      f  [  id , z  !  , (id ×₁ s) ]  M._≅_.from nno-iso     ≈⟨ pullˡ ∘[]  
      [ f   id , z  !  , f  (id ×₁ s) ]  M._≅_.from nno-iso ≈⟨ ([]-cong₂ IB IS) ⟩∘⟨refl  
      [ g   id , z  !  , g  (id ×₁ s) ]  M._≅_.from nno-iso ≈˘⟨ pullˡ ∘[]  
      g  [  id , z  !  , (id ×₁ s) ]  M._≅_.from nno-iso     ≈⟨ elimʳ (M._≅_.isoˡ nno-iso)  
      g                                                           

    u : D₀ (X × N) × D₀   D₀ (X × N) + D₀ (X × N) × D₀ 
    u = [ (i₁  π₁) , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out)

    u-now : u  (id ×₁ now)  i₁  π₁
    u-now = begin 
      u  (id ×₁ now) ≈⟨ pullʳ (pullʳ (×₁∘×₁  ×₁-cong₂ identity² unitlaw))  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₁) ≈⟨ refl⟩∘⟨ distributeˡ⁻¹-i₁  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  i₁ ≈⟨ inject₁  
      i₁  π₁ 

    u-later : u  (later ×₁ later)  i₂
    u-later = begin 
      u  (later ×₁ later)                                                                                                             ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
      u  (id ×₁ later)  (later ×₁ id)                                                                                                ≈⟨ pullʳ (pullʳ (pullˡ (×₁∘×₁  ×₁-cong₂ identity² laterlaw)))  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₂)  (later ×₁ id) ≈⟨ refl⟩∘⟨ (pullˡ distributeˡ⁻¹-i₂)  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  i₂  (later ×₁ id)                         ≈⟨ extendʳ inject₂  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  (distributeʳ⁻¹  (out ×₁ id))  (later ×₁ id)                                          ≈⟨ refl⟩∘⟨ (pullʳ (×₁∘×₁  ×₁-cong₂ laterlaw identity²)) 
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (i₂ ×₁ id)                                                             ≈⟨ refl⟩∘⟨ distributeʳ⁻¹-i₂  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  i₂                                                                                     ≈⟨ inject₂  
      i₂                                                                                                                               

    u-zero : u  (now   id , z  !  ×₁ later)  i₂  (now   id , z  !  ×₁ id)
    u-zero = begin 
      ([ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out))  (now   id , z  !  ×₁ later)              ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
      ([ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out))  (id ×₁ later)  (now   id , z  !  ×₁ id) ≈⟨ pullʳ (pullʳ (pullˡ (×₁∘×₁  ×₁-cong₂ identity² laterlaw)))  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₂)  (now   id , z  !  ×₁ id)                    ≈⟨ refl⟩∘⟨ (pullˡ distributeˡ⁻¹-i₂)  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  i₂  (now   id , z  !  ×₁ id)                                            ≈⟨ extendʳ inject₂  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  (distributeʳ⁻¹  (out ×₁ id))  (now   id , z  !  ×₁ id)                                                             ≈⟨ refl⟩∘⟨ (pullʳ (×₁∘×₁  ×₁-cong₂ (pullˡ unitlaw) refl  sym ×₁∘×₁))  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (i₁ ×₁ id)  ( id , z  !  ×₁ id)                                                                      ≈⟨ refl⟩∘⟨ (pullˡ distributeʳ⁻¹-i₁)  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  i₁  ( id , z  !  ×₁ id)                                                                                              ≈⟨ extendʳ inject₁  
      i₂  (now  (id ×₁ s⁻¹) ×₁ id)  ( id , z  !  ×₁ id)                                                                                                            ≈⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ (pullʳ (×₁∘⟨⟩  ⟨⟩-cong₂ identity² (pullˡ s⁻¹-zero))) identity²)  
      i₂  (now   id , z  !  ×₁ id)                                                                                                                                  

    u-succ : u  (now  (id ×₁ s) ×₁ later)  i₂  (now ×₁ id)
    u-succ = begin 
      ([ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out))  (now  (id ×₁ s) ×₁ later)              ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ) 
      ([ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out))  (id ×₁ later)  (now  (id ×₁ s) ×₁ id) ≈⟨ pullʳ (pullʳ (pullˡ (×₁∘×₁  ×₁-cong₂ identity² laterlaw)))  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₂)  (now  (id ×₁ s) ×₁ id)                    ≈⟨ refl⟩∘⟨ (pullˡ distributeˡ⁻¹-i₂)  
      [ i₁  π₁ , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  i₂  (now  (id ×₁ s) ×₁ id)                                            ≈⟨ extendʳ inject₂  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  (distributeʳ⁻¹  (out ×₁ id))  (now  (id ×₁ s) ×₁ id)                                                             ≈⟨ refl⟩∘⟨ (pullʳ (×₁∘×₁  ×₁-cong₂ (pullˡ unitlaw) refl  sym ×₁∘×₁))  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (i₁ ×₁ id)  ((id ×₁ s) ×₁ id)                                                                      ≈⟨ refl⟩∘⟨ (pullˡ distributeʳ⁻¹-i₁)  
      [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  i₁  ((id ×₁ s) ×₁ id)                                                                                              ≈⟨ extendʳ inject₁  
      i₂  (now  (id ×₁ s⁻¹) ×₁ id)  ((id ×₁ s) ×₁ id)                                                                                                            ≈⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ (cancelʳ (×₁∘×₁  ×₁-cong₂ identity² s⁻¹-succ  ⟨⟩-unique id-comm id-comm)) identity²)  
      i₂  (now ×₁ id)                                                                                                                                              

    coit-w-retract : coit w   D.μ.η X , D₁ !   id
    coit-w-retract = begin 
      coit w   D.μ.η X , D₁ !  ≈˘⟨ coit-unique out (coit w   D.μ.η X , D₁ ! ) coit-helper  
      coit out                    ≈⟨ coit-refl  
      id                          
      where
      coit-helper : out  coit w   D.μ.η X , D₁ !   (id +₁ coit w   D.μ.η X , D₁ ! )  out
      coit-helper = begin 
        out  coit w   D.μ.η X , D₁ !                  ≈⟨ extendʳ (coit-commutes w)  
        (id +₁ coit w)  w   D.μ.η X , D₁ !            ≈⟨ refl⟩∘⟨ (D-jointly-epic now-helper later-helper)  
        (id +₁ coit w)  (id +₁  D.μ.η X , D₁ ! )  out ≈⟨ pullˡ (+₁∘+₁  +₁-cong₂ identity² refl)  
        (id +₁ coit w   D.μ.η X , D₁ ! )  out         
        where
        now-helper : (w   D.μ.η X , D₁ ! )  now  ((id +₁  D.μ.η X , D₁ ! )  out)  now
        now-helper = begin 
          (w   D.μ.η X , D₁ ! )  now           ≈⟨ pullʳ (⟨⟩∘  ⟨⟩-cong₂ D.identityʳ (sym (D.η.commute !)))  
          w   id , now  !                      ≈˘⟨ refl⟩∘⟨ (×₁∘⟨⟩  ⟨⟩-congʳ identity²)  
          w  (id ×₁ now)   id , !              ≈⟨ extendʳ w-now 
          i₁  π₁   id , !                      ≈⟨ elimʳ project₁ 
          i₁                                       ≈˘⟨ inject₁  identityʳ  
          (id +₁  D.μ.η X , D₁ ! )  i₁          ≈˘⟨ pullʳ unitlaw  
          ((id +₁  D.μ.η X , D₁ ! )  out)  now 
        later-helper : (w   D.μ.η X , D₁ ! )  later  ((id +₁  D.μ.η X , D₁ ! )  out)  later
        later-helper = begin 
          (w   D.μ.η X , D₁ ! )  later                  ≈⟨ pullʳ (⟨⟩∘  ⟨⟩-cong₂ (sym identityˡ) (sym (later-extend-comm (now  !)))  sym ×₁∘⟨⟩)  
          w  (id ×₁ later)   D.μ.η X  later , D₁ !     ≈⟨ extendʳ w-later  
          i₂  (earlier ×₁ id)   D.μ.η X  later , D₁ !  ≈⟨ refl⟩∘⟨ (×₁∘⟨⟩  ⟨⟩-cong₂ (∘-resp-≈ʳ (sym (later-extend-comm id))  cancelˡ earlier∘later) identityˡ)  
          i₂   D.μ.η X , D₁ !                            ≈˘⟨ inject₂  
          (id +₁  D.μ.η X , D₁ ! )  i₂                   ≈˘⟨ pullʳ laterlaw  
          ((id +₁  D.μ.η X , D₁ ! )  out)  later        

    w-u-commute :  (h : X × N  D₀ X)  h  (id ×₁ s⁻¹)  earlier  h  w  (extend h ×₁ id)  (extend h +₁ (extend h ×₁ id))  u
    w-u-commute h earlier-s⁻¹ = sym (D-jointly-epic-product case₁ case₂ case₃ case₄)
      where 
      case₁₂ : ((extend h +₁ (extend h ×₁ id))  u)  (id ×₁ now)  (w  (extend h ×₁ id))  (id ×₁ now)
      case₁₂ = begin 
        ((extend h +₁ (extend h ×₁ id))  u)  (id ×₁ now) ≈⟨ pullʳ u-now  
        (extend h +₁ (extend h ×₁ id))  i₁  π₁           ≈⟨ extendʳ inject₁  
        i₁  extend h  π₁                                 ≈˘⟨ refl⟩∘⟨ project₁  
        i₁  π₁  (extend h ×₁ id)                         ≈˘⟨ extendʳ w-now  
        w  (id ×₁ now)  (extend h ×₁ id)                 ≈˘⟨ pullʳ (×₁∘×₁  ×₁-cong₂ id-comm id-comm-sym  sym ×₁∘×₁)  
        (w  (extend h ×₁ id))  (id ×₁ now)               
      case₁ : ((extend h +₁ (extend h ×₁ id))  u)  (now ×₁ now)  (w  (extend h ×₁ id))  (now ×₁ now)
      case₁ = begin 
        ((extend h +₁ (extend h ×₁ id))  u)  (now ×₁ now)              ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
        ((extend h +₁ (extend h ×₁ id))  u)  (id ×₁ now)  (now ×₁ id) ≈⟨ extendʳ case₁₂  
        (w  (extend h ×₁ id))  (id ×₁ now)  (now ×₁ id)               ≈⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
        (w  (extend h ×₁ id))  (now ×₁ now)                            
      case₂ : ((extend h +₁ (extend h ×₁ id))  u)  (later ×₁ now)  (w  (extend h ×₁ id))  (later ×₁ now)
      case₂ = begin 
        ((extend h +₁ (extend h ×₁ id))  u)  (later ×₁ now)              ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
        ((extend h +₁ (extend h ×₁ id))  u)  (id ×₁ now)  (later ×₁ id) ≈⟨ extendʳ case₁₂  
        (w  (extend h ×₁ id))  (id ×₁ now)  (later ×₁ id)               ≈⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
        (w  (extend h ×₁ id))  (later ×₁ now)                            
      case₃ : ((extend h +₁ (extend h ×₁ id))  u)  (now ×₁ later)  (w  (extend h ×₁ id))  (now ×₁ later)
      case₃ = begin 
        ((extend h +₁ (extend h ×₁ id))  u)  (now ×₁ later)                                                                                                               ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ)  
        ((extend h +₁ (extend h ×₁ id))  u)  (id ×₁ later)  (now ×₁ id)                                                                                                  ≈⟨ pullʳ (pullˡ (pullʳ (pullʳ (×₁∘×₁  ×₁-cong₂ identity² laterlaw))))  
        (extend h +₁ (extend h ×₁ id))  ([ (i₁  π₁) , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  distributeˡ⁻¹  (id ×₁ i₂))  (now ×₁ id) ≈⟨ refl⟩∘⟨ ((refl⟩∘⟨ distributeˡ⁻¹-i₂) ⟩∘⟨refl)  
        (extend h +₁ (extend h ×₁ id))  ([ (i₁  π₁) , [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id) ]  i₂)  (now ×₁ id)                         ≈⟨ refl⟩∘⟨ (∘-resp-≈ˡ inject₂  assoc²βε)  
        (extend h +₁ (extend h ×₁ id))  [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (out ×₁ id)  (now ×₁ id)                                                ≈⟨ refl⟩∘⟨ refl⟩∘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ unitlaw identity²)  
        (extend h +₁ (extend h ×₁ id))  [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  distributeʳ⁻¹  (i₁ ×₁ id)                                                               ≈⟨ refl⟩∘⟨ refl⟩∘⟨ distributeʳ⁻¹-i₁  
        (extend h +₁ (extend h ×₁ id))  [ i₂  (now  (id ×₁ s⁻¹) ×₁ id) , i₂ ]  i₁                                                                                       ≈⟨ refl⟩∘⟨ inject₁  
        (extend h +₁ (extend h ×₁ id))  i₂  (now  (id ×₁ s⁻¹) ×₁ id)                                                                                                     ≈⟨ extendʳ inject₂  
        i₂  (extend h ×₁ id)  (now  (id ×₁ s⁻¹) ×₁ id)                                                                                                                   ≈⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ (pullˡ DK.identityʳ) identity²)  
        i₂  (h  (id ×₁ s⁻¹) ×₁ id)                                                                                                                                        ≈⟨ refl⟩∘⟨ ×₁-cong₂ earlier-s⁻¹ refl  
        i₂  (earlier  h ×₁ id)                                                                                                                                            ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ refl identity²)  
        i₂  (earlier ×₁ id)  (h ×₁ id)                                                                                                                                    ≈˘⟨ extendʳ w-later  
        w  (id ×₁ later)  (h ×₁ id)                                                                                                                                       ≈˘⟨ pullʳ (×₁∘×₁  ×₁-cong₂ (DK.identityʳ  sym identityˡ) id-comm-sym  sym ×₁∘×₁)  
        (w  (extend h ×₁ id))  (now ×₁ later)                                                                                                                             
      case₄ : ((extend h +₁ (extend h ×₁ id))  u)  (later ×₁ later)  (w  (extend h ×₁ id))  (later ×₁ later)
      case₄ = begin 
        ((extend h +₁ (extend h ×₁ id))  u)  (later ×₁ later) ≈⟨ pullʳ u-later  
        (extend h +₁ (extend h ×₁ id))  i₂                     ≈⟨ inject₂  
        i₂  (extend h ×₁ id)                                   ≈˘⟨ refl⟩∘⟨ (×₁∘×₁  ×₁-cong₂ (∘-resp-≈ʳ (sym (later-extend-comm h))  cancelˡ earlier∘later) identity²)  
        i₂  (earlier ×₁ id)  (extend h  later ×₁ id)         ≈˘⟨ extendʳ w-later  
        w  (id ×₁ later)  (extend h  later ×₁ id)            ≈˘⟨ pullʳ (×₁∘×₁  ×₁-cong₂ (sym identityˡ) id-comm-sym  sym ×₁∘×₁)  
        (w  (extend h ×₁ id))  (later ×₁ later)               

    coit-w-u-commute-ι : coit w  (extend ι ×₁ id)  D₁ (extend ι)  coit u
    coit-w-u-commute-ι = begin 
      coit w  (extend ι ×₁ id)   ≈˘⟨ coit-unique ((extend ι +₁ id)  u) (coit w  (extend ι ×₁ id)) unique₁  
      coit ((extend ι +₁ id)  u) ≈⟨ coit-unique ((extend ι +₁ id)  u) (D₁ (extend ι)  coit u) unique₂  
      D₁ (extend ι)  coit u      
      where
      earlier-s⁻¹ : ι  (id ×₁ s⁻¹)  earlier  ι {X}
      earlier-s⁻¹ = begin 
        ι  (id ×₁ s⁻¹) ≈⟨ PNNO-jointly-epic IB IS  
        earlier  ι {X} 
        where
        IB : (ι  (id ×₁ s⁻¹))   id , z  !   (earlier  ι {X})   id , z  ! 
        IB = begin 
          (ι  (id ×₁ s⁻¹))   id , z  !   ≈⟨ pullʳ (×₁∘⟨⟩  ⟨⟩-cong₂ identity² (pullˡ s⁻¹-zero))  
          ι   id , z  !                   ≈⟨ ι-zero  
          now                                 ≈˘⟨ inject₁ 
          [ now , id ]  i₁                   ≈˘⟨ pullʳ unitlaw  
          ([ now , id ]  out)  now          ≈˘⟨ pullʳ ι-zero  
          (earlier  ι {X})   id , z  !   
        IS : (ι  (id ×₁ s⁻¹))  (id ×₁ s)  (earlier  ι {X})  (id ×₁ s)
        IS = begin 
          (ι  (id ×₁ s⁻¹))  (id ×₁ s) ≈⟨ cancelʳ (×₁∘×₁  ×₁-cong₂ identity² s⁻¹-succ  ⟨⟩-unique id-comm id-comm)  
          ι                             ≈˘⟨ cancelˡ earlier∘later 
          earlier  later  ι           ≈˘⟨ pullʳ ι-succ 
          (earlier  ι)  (id ×₁ s)     
      unique₁ : out  coit w  (extend ι ×₁ id)  (id +₁ coit w  (extend ι ×₁ id))  (extend ι +₁ id)  u
      unique₁ = begin 
        out  coit w  (extend ι ×₁ id)                          ≈⟨ extendʳ (coit-commutes w)  
        (id +₁ coit w)  w  (extend ι ×₁ id)                    ≈⟨ refl⟩∘⟨ w-u-commute ι earlier-s⁻¹  
        (id +₁ coit w)  (extend ι +₁ (extend ι ×₁ id))  u      ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ refl (sym identityʳ)  sym +₁∘+₁)  
        (id +₁ coit w  (extend ι ×₁ id))  (extend ι +₁ id)  u 
      unique₂ : out  D₁ (extend ι)  coit u  (id +₁ D₁ (extend ι)  coit u)  (extend ι +₁ id)  u
      unique₂ = begin 
        out  D₁ (extend ι)  coit u                          ≈⟨ extendʳ (D₁-commutes (extend ι))  
        (extend ι +₁ D₁ (extend ι))  out  coit u            ≈⟨ refl⟩∘⟨ (coit-commutes u)  
        (extend ι +₁ D₁ (extend ι))  (id +₁ coit u)  u      ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ id-comm (sym identityʳ)  sym +₁∘+₁)  
        (id +₁ D₁ (extend ι)  coit u)  (extend ι +₁ id)  u 

    coit-w-u-commute-Dπ₁ : coit w  (D₁ π₁ ×₁ id)  D₁ (D₁ π₁)  coit u
    coit-w-u-commute-Dπ₁ = begin 
      coit w  (D₁ π₁ ×₁ id)   ≈˘⟨ coit-unique ((D₁ π₁ +₁ id)  u) (coit w  (D₁ π₁ ×₁ id)) unique₁  
      coit ((D₁ π₁ +₁ id)  u) ≈⟨ coit-unique ((D₁ π₁ +₁ id)  u) (D₁ (D₁ π₁)  coit u) unique₂  
      D₁ (D₁ π₁)  coit u      
      where
      earlier-s⁻¹ : (now  π₁)  (id ×₁ s⁻¹)  earlier  (now  π₁)
      earlier-s⁻¹ = begin 
        (now  π₁)  (id ×₁ s⁻¹) ≈⟨ pullʳ (project₁  identityˡ) 
        now  π₁                 ≈˘⟨ pullˡ earlier∘now  
        earlier  (now  π₁)     
      unique₁ : out  coit w  (D₁ π₁ ×₁ id)  (id +₁ coit w  (D₁ π₁ ×₁ id))  (D₁ π₁ +₁ id)  u
      unique₁ = begin 
        out  coit w  (D₁ π₁ ×₁ id)                       ≈⟨ extendʳ (coit-commutes w)  
        (id +₁ coit w)  w  (D₁ π₁ ×₁ id)                 ≈⟨ refl⟩∘⟨ (w-u-commute (now  π₁) earlier-s⁻¹)  
        (id +₁ coit w)  (D₁ π₁ +₁ (D₁ π₁ ×₁ id))  u      ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ refl (sym identityʳ)  sym +₁∘+₁)  
        (id +₁ coit w  (D₁ π₁ ×₁ id))  (D₁ π₁ +₁ id)  u 
      unique₂ : out  D₁ (D₁ π₁)  coit u  (id +₁ D₁ (D₁ π₁)  coit u)  (D₁ π₁ +₁ id)  u
      unique₂ = begin
        out  D₁ (D₁ π₁)  coit u                       ≈⟨ extendʳ (D₁-commutes (D₁ π₁))  
        (D₁ π₁ +₁ D₁ (D₁ π₁))  out  coit u            ≈⟨ refl⟩∘⟨ (coit-commutes u)  
        (D₁ π₁ +₁ D₁ (D₁ π₁))  (id +₁ coit u)  u      ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ id-comm (sym identityʳ)  sym +₁∘+₁)  
        (id +₁ D₁ (D₁ π₁)  coit u)  (D₁ π₁ +₁ id)  u 

    coit-w-ρ : D₁ ρ  coit w  D₁ π₁  τ  (ρ ×₁ id)
    coit-w-ρ = begin 
      D₁ ρ  coit w         ≈˘⟨ coit-unique ((ρ +₁ id)  w) (D₁ ρ  coit w) unique₁  
      coit ((ρ +₁ id)  w)  ≈⟨ coit-unique ((ρ +₁ id)  w) (D₁ π₁  τ  (ρ ×₁ id)) unique₂  
      D₁ π₁  τ  (ρ ×₁ id) 
      where
      unique₁ : out  D₁ ρ  coit w  (id +₁ D₁ ρ  coit w)  (ρ +₁ id)  w
      unique₁ = begin 
        out  D₁ ρ  coit w ≈⟨ extendʳ (D₁-commutes ρ)  
        (ρ +₁ D₁ ρ)  out  coit w            ≈⟨ refl⟩∘⟨ coit-commutes w  
        (ρ +₁ D₁ ρ)  (id +₁ coit w)  w      ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ id-comm (sym identityʳ)  sym +₁∘+₁)  
        (id +₁ D₁ ρ  coit w)  (ρ +₁ id)  w 
      unique₂ : out  D₁ π₁  τ  (ρ ×₁ id)  (id +₁ D₁ π₁  τ  (ρ ×₁ id))  (ρ +₁ id)  w
      unique₂ = begin 
        out  D₁ π₁  τ  (ρ ×₁ id)                                                ≈⟨ extendʳ (D₁-commutes π₁)  
        (π₁ +₁ D₁ π₁)  out  τ  (ρ ×₁ id)                                        ≈⟨ refl⟩∘⟨ extendʳ τ-commutes  
        (π₁ +₁ D₁ π₁)  (id +₁ τ)  (distributeˡ⁻¹  (id ×₁ out))  (ρ ×₁ id)      ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ id-comm (sym identityʳ)  sym +₁∘+₁)  
        (id +₁ D₁ π₁  τ)  (π₁ +₁ id)  (distributeˡ⁻¹  (id ×₁ out))  (ρ ×₁ id) ≈⟨ refl⟩∘⟨ refl⟩∘⟨ (pullʳ (×₁∘×₁  ×₁-cong₂ identityˡ identityʳ))  
        (id +₁ D₁ π₁  τ)  (π₁ +₁ id)  distributeˡ⁻¹  (ρ ×₁ out)                ≈⟨ refl⟩∘⟨ helper  
        (id +₁ D₁ π₁  τ)  (ρ +₁ (ρ ×₁ id))  w                                   ≈⟨ extendʳ (+₁∘+₁  +₁-cong₂ refl (assoc  sym identityʳ)  sym +₁∘+₁)  
        (id +₁ D₁ π₁  τ  (ρ ×₁ id))  (ρ +₁ id)  w                              
        where
        helper : (π₁ +₁ id)  distributeˡ⁻¹  (ρ ×₁ out)  (ρ +₁ (ρ ×₁ id))  w
        helper = sym (begin 
          (ρ +₁ (ρ ×₁ id))  [ i₁  π₁ , i₂  (earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out) ≈⟨ pullˡ (∘[]  []-cong₂ (extendʳ inject₁) (extendʳ inject₂  ∘-resp-≈ʳ (×₁∘×₁  ×₁-cong₂ refl identity²)))  
          [ i₁  ρ  π₁ , i₂  (ρ  earlier ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out)            ≈˘⟨ ([]-cong₂ (∘-resp-≈ʳ project₁) (∘-resp-≈ʳ (×₁-cong₂ (sym ρ-earlier) refl))) ⟩∘⟨refl  
          [ i₁  π₁  (ρ ×₁ id) , i₂  (ρ ×₁ id) ]  distributeˡ⁻¹  (id ×₁ out)              ≈˘⟨ pullˡ ([]∘+₁  []-cong₂ assoc refl) 
          [ i₁  π₁ , i₂ ]  (ρ ×₁ id +₁ ρ ×₁ id)  distributeˡ⁻¹  (id ×₁ out)               ≈⟨ refl⟩∘⟨ (extendʳ (distributeˡ⁻¹-natural ρ id id))  
          [ i₁  π₁ , i₂ ]  distributeˡ⁻¹  (ρ ×₁ (id +₁ id))  (id ×₁ out)                  ≈⟨ ([]-cong₂ refl (sym identityʳ)) ⟩∘⟨ ∘-resp-≈ʳ (×₁∘×₁  ×₁-cong₂ identityʳ (elimˡ ([]-unique id-comm-sym id-comm-sym)))  
         (π₁ +₁ id)  distributeˡ⁻¹  (ρ ×₁ out)                                              )

  3⇒1 : (∀ X  cond-3 X)  cond-1
  3⇒1 c-3 X = record
    { equality = sym D.F.homomorphism  D.F.F-resp-≈ (Coequalizer.equality (coeqs X))  D.F.homomorphism
    ; coequalize = b
    ; universal = λ {Z} {h} {eq}  universal' eq 
    ; unique = λ {Z} {h} {i} {eq} i-universal  epi-Dρ (Search-Algebra.search-algebra-on (Elgot⇒Search (record { A = Ď₀ X ; algebra = elgot }))) i (b eq) (sym i-universal  universal' eq)
    }
    where
      open cond-3 (c-3 X) using (elgot; ρ-algebra-morphism)
      open Search-Algebra (Elgot⇒Search (record { A = Ď₀ X ; algebra = elgot })) using (α)
      open import Monad.Instance.Delay.Quotient.Epis distributive DM PNNO DQ
      module CP = IsCoequalizer (coeq-productsˡ {X} {D₀ } (id))
      module _ {Y : Obj} {a : D₀ (D₀ X)  Y} (eq : a  D₁ (extend ι)  a  D₁ (D₁ π₁)) where
        c : Ď₀ X × D₀   Y
        c = CP.coequalize (begin 
          (a  coit w)  (extend ι ×₁ id) ≈⟨ pullʳ coit-w-u-commute-ι  
          a  D₁ (extend ι)  coit u      ≈⟨ extendʳ eq  
          a  D₁ (D₁ π₁)  coit u         ≈˘⟨ pullʳ coit-w-u-commute-Dπ₁  
          (a  coit w)  (D₁ π₁ ×₁ id)    )
        b : D₀ (Ď₀ X)  Y
        b = c   α , D₁ ! 
        universal' : a  b  D₁ ρ
        universal' = sym (begin 
          b  D₁ ρ                                             ≈⟨ introʳ coit-w-retract  
          (b  D₁ ρ)  coit w   D.μ.η _ , D₁ !              ≈⟨ pullʳ (extendʳ coit-w-ρ)  
          b  D₁ π₁  (τ  (ρ ×₁ id))   D.μ.η _ , D₁ !      ≈⟨ refl⟩∘⟨ refl⟩∘⟨ pullʳ upper-square  
          (c   α , D₁ ! )  D₁ π₁  τ   α , D₁ !   D₁ ρ ≈⟨ refl⟩∘⟨ (sym-assoc  cancelˡ (assoc  retract-helper)) 
          (c   α , D₁ ! )  D₁ ρ                            ≈⟨ pullʳ (sym upper-square)  
          c  (ρ ×₁ id)   D.μ.η _ , D₁ !                    ≈˘⟨ extendʳ CP.universal  
          a  coit w   D.μ.η _ , D₁ !                       ≈⟨ elimʳ coit-w-retract  
          a                                                    )
          where
          open import Algebra.Search.Retraction distributive DM using (tau-retract)
          retract-helper : D₁ π₁  τ   α , D₁ !   id
          retract-helper = begin 
            D₁ π₁  τ   α , D₁ !                           ≈˘⟨ refl⟩∘⟨ refl⟩∘⟨ elimʳ (sym D.F.homomorphism  D.F.F-resp-≈ (Iso.isoʳ (_≅_.iso A×⊤≅A))  D.F.identity)  
            D₁ π₁  τ   α , D₁ !   D₁ π₁  D₁  id , !   ≈⟨ refl⟩∘⟨ refl⟩∘⟨ pullˡ (⟨⟩∘  ⟨⟩-congˡ (sym D.F.homomorphism  D.F.F-resp-≈ !-unique₂))  
            D₁ π₁  τ   α  D₁ π₁ , D₁ π₂   D₁  id , !  ≈⟨ refl⟩∘⟨ (cancelˡ (Retract.is-retract (tau-retract  (Elgot⇒Search (record { A = Ď₀ X ; algebra = elgot })))))  
            D₁ π₁  D₁  id , !                              ≈⟨ sym D.F.homomorphism  D.F.F-resp-≈ (Iso.isoʳ (_≅_.iso A×⊤≅A))  D.F.identity  
            id                                                
          upper-square : (ρ ×₁ id)   D.μ.η _ , D₁ !    α , D₁ !   D₁ ρ
          upper-square = ×₁∘⟨⟩  ⟨⟩-cong₂ ρ-algebra-morphism (identityˡ  D.F.F-resp-≈ (!-unique (!  ρ))  D.F.homomorphism)  sym ⟨⟩∘