{-# OPTIONS --without-K --rewriting #-}

open import lib.Basics
open import lib.two-semi-categories.Functor
open import lib.two-semi-categories.FundamentalCategory
open import lib.two-semi-categories.FunctorInverse
open import lib.types.Pi using ()

module lib.two-semi-categories.FunextFunctors where

module FunextFunctors {i j} (A : Type i) (B : Type j) {{B-level : has-level 2 B}} where

  open import lib.two-semi-categories.FunCategory

  private

    app=-pres-comp :  {f g h : A  B} (α : f == g) (β : g == h)  app= (α  β) ==  a  app= α a  app= β a)
    app=-pres-comp α β = λ=  a  ap-∙  f  f a) α β)

    abstract
      app=-pres-comp-coh :  {f g h i : A  B} (α : f == g) (β : g == h) (γ : h == i)
         app=-pres-comp (α  β) γ ◃∙
          ap  s a  s a  app= γ a) (app=-pres-comp α β) ◃∙
          λ=  a  ∙-assoc (app= α a) (app= β a) (app= γ a)) ◃∎
          =ₛ
          ap app= (∙-assoc α β γ) ◃∙
          app=-pres-comp α (β  γ) ◃∙
          ap  s a  app= α a  s a) (app=-pres-comp β γ) ◃∎
      app=-pres-comp-coh {f} idp idp γ =
        app=-pres-comp idp γ ◃∙
        ap  s a  s a  app= γ a) (app=-pres-comp idp idp) ◃∙
        λ=  a  idp) ◃∎
          =ₛ⟨ 2 & 1 & =ₛ-in {t = []} (! (λ=-η idp)) 
        app=-pres-comp idp γ ◃∙
        ap  s a  s a  app= γ a) (λ=  a  idp {a = idp {a = f a}})) ◃∎
          =ₛ₁⟨ 1 & 1 & ap (ap  s a  s a  app= γ a)) (! (λ=-η idp)) 
        app=-pres-comp idp γ ◃∙
        idp ◃∎
          =ₛ₁⟨ 1 & 1 & ap (ap  s  s)) (λ=-η idp) 
        app=-pres-comp idp γ ◃∙
        ap  s  s) (λ=  a  idp {a = app= γ a})) ◃∎
          =ₛ⟨ 0 & 0 & contract 
        idp ◃∙
        app=-pres-comp idp γ ◃∙
        ap  s  s) (λ=  a  idp {a = app= γ a})) ◃∎ ∎ₛ

  app=-functor : TwoSemiFunctor (2-type-fundamental-cat (A  B))
                                (fun-cat A (2-type-fundamental-cat B))
  app=-functor =
    record
    { F₀ = idf (A  B)
    ; F₁ = app=
    ; pres-comp = app=-pres-comp
    ; pres-comp-coh = app=-pres-comp-coh
    }

  private
    module app=-functor =
      TwoSemiFunctor app=-functor
    module app=-inverse =
      FunctorInverse
        app=-functor
        (idf-is-equiv _)
         f g  snd app=-equiv)

  λ=-functor : TwoSemiFunctor (fun-cat A (2-type-fundamental-cat B))
                              (2-type-fundamental-cat (A  B))
  λ=-functor = app=-inverse.functor

  module λ=-functor = TwoSemiFunctor λ=-functor

  abstract
    λ=-functor-pres-comp=λ=-∙ :  {f g h : A  B} (α : f  g) (β : g  h)
       λ=-functor.pres-comp α β == =ₛ-out (λ=-∙ α β)
    λ=-functor-pres-comp=λ=-∙ α β = =ₛ-out {t = =ₛ-out (λ=-∙ α β) ◃∎} $
      λ=-functor.pres-comp α β ◃∎
        =ₛ⟨ app=-inverse.pres-comp-β α β 
      idp ◃∙
      ap2  s t  λ=  a  s a  t a)) (! (λ= (app=-β α))) (! (λ= (app=-β β))) ◃∙
      ap λ= (! (λ=  a  ap-∙  f  f a) (λ= α) (λ= β)))) ◃∙
      ! (λ=-η (λ= α  λ= β)) ◃∎
        =ₛ⟨ 0 & 1 & expand [] 
      ap2  s t  λ=  a  s a  t a)) (! (λ= (app=-β α))) (! (λ= (app=-β β))) ◃∙
      ap λ= (! (λ=  a  ap-∙  f  f a) (λ= α) (λ= β)))) ◃∙
      ! (λ=-η (λ= α  λ= β)) ◃∎
        =ₛ₁⟨ 0 & 1 & step₈ 
      ap λ= (! (λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a')))) ◃∙
      ap λ= (! (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β)))) ◃∙
      ! (λ=-η (λ= α  λ= β)) ◃∎
        =ₛ⟨ 0 & 2 &
            ap-seq-=ₛ λ= $ ∙-!-seq $
            λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β)) ◃∙
            λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a')) ◃∎ 
      ap λ= (! (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β)) 
                λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a')))) ◃∙
      ! (λ=-η (λ= α  λ= β)) ◃∎
        =ₛ₁⟨ 0 & 1 & ap-! λ= (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β)) 
                              λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a'))) 
      ! (ap λ= (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β)) 
                λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a')))) ◃∙
      ! (λ=-η (λ= α  λ= β)) ◃∎
        =ₛ₁⟨ 0 & 1 &
            ap (!  ap λ=) $ =ₛ-out $
            ∙-λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β))
                   a'  ap2 _∙_ (app=-β α a') (app=-β β a')) 
      ! (ap λ= (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β) 
                          ap2 _∙_ (app=-β α a') (app=-β β a')))) ◃∙
      ! (λ=-η (λ= α  λ= β)) ◃∎
        =ₛ⟨ =ₛ-in $
            ∙-! (ap λ= (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β) 
                                          ap2 _∙_ (app=-β α a') (app=-β β a'))))
                (λ=-η (λ= α  λ= β)) 
      ! (λ=-η (λ= α  λ= β) 
        ap λ= (λ=  a'  ap-∙  γ  γ a') (λ= α) (λ= β) 
                          ap2 _∙_ (app=-β α a') (app=-β β a')))) ◃∎ ∎ₛ
      where
      step₈' : ap2  s t a  s a  t a) (λ= (app=-β α)) (λ= (app=-β β)) ==
              λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a'))
      step₈' =
        –>-is-inj app=-equiv _ _ $ λ= $ λ a 
        app= (ap2  s t a'  s a'  t a') (λ= (app=-β α)) (λ= (app=-β β))) a
          =⟨ ap-ap2  f  f a)  s t a'  s a'  t a') (λ= (app=-β α)) (λ= (app=-β β)) 
        ap2  s t  s a  t a) (λ= (app=-β α)) (λ= (app=-β β))
          =⟨ ! (ap2-ap-lr _∙_  f  f a)  f  f a) (λ= (app=-β α)) (λ= (app=-β β))) 
        ap2 _∙_ (app= (λ= (app=-β α)) a) (app= (λ= (app=-β β)) a)
          =⟨ ap2 (ap2 _∙_) (app=-β (app=-β α) a) (app=-β (app=-β β) a) 
        ap2 _∙_ (app=-β α a) (app=-β β a)
          =⟨ ! (app=-β  a'  ap2 _∙_ (app=-β α a') (app=-β β a')) a) 
        app= (λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a'))) a =∎
      step₈ : ap2  s t  λ=  a  s a  t a)) (! (λ= (app=-β α))) (! (λ= (app=-β β))) ==
              ap λ= (! (λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a'))))
      step₈ =
        ap2  s t  λ=  a  s a  t a)) (! (λ= (app=-β α))) (! (λ= (app=-β β)))
          =⟨ ! (ap-ap2 λ=  s t a  s a  t a) (! (λ= (app=-β α))) (! (λ= (app=-β β)))) 
        ap λ= (ap2  s t a  s a  t a) (! (λ= (app=-β α))) (! (λ= (app=-β β))))
          =⟨ ap (ap λ=) (ap2-!  s t a  s a  t a) (λ= (app=-β α)) (λ= (app=-β β))) 
        ap λ= (! (ap2  s t a  s a  t a) (λ= (app=-β α)) (λ= (app=-β β))))
          =⟨ ap (ap λ=  !) step₈' 
        ap λ= (! (λ=  a'  ap2 _∙_ (app=-β α a') (app=-β β a')))) =∎