module GpdCont.TwoCategory.Displayed.Base where

open import GpdCont.Prelude
open import GpdCont.TwoCategory.Base
open import GpdCont.TwoCategory.LaxFunctor
open import GpdCont.TwoCategory.StrictFunctor

open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma using (Σ≡Prop)

module _ {ℓo ℓh ℓr} (C : TwoCategory ℓo ℓh ℓr) (ℓoᴰ ℓhᴰ ℓrᴰ : Level) where
  private
    ℓC = ℓ-of C
    ℓCᴰ : Level
    ℓCᴰ = ℓMax ℓoᴰ ℓhᴰ ℓrᴰ
    module C = TwoCategory C

  module _
    (ob[_] : C.ob  Type ℓoᴰ)
    (hom[_] : {x y : C.ob} (f : C.hom x y) (xᴰ : ob[ x ]) (yᴰ : ob[ y ])  Type ℓhᴰ)
    (rel[_] : {x y : C.ob} {f g : C.hom x y}
       {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
       (s : C.rel f g)
       (fᴰ : hom[ f ] xᴰ yᴰ)
       (gᴰ : hom[ g ] xᴰ yᴰ)
       Type ℓrᴰ)
    where
      open C
      record TwoCategoryStrᴰ : Type (ℓ-max ℓC ℓCᴰ) where
        no-eta-equality
        field
          id-homᴰ :  {x} (xᴰ : ob[ x ])  hom[ id-hom x ] xᴰ xᴰ
          comp-homᴰ :  {x y z} {f : hom x y} {g : hom y z}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]} {zᴰ : ob[ z ]}
             (fᴰ : hom[ f ] xᴰ yᴰ)
             (gᴰ : hom[ g ] yᴰ zᴰ)
             hom[ comp-hom f g ] xᴰ zᴰ

        field
          id-relᴰ :  {x y} {f : hom x y}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             (fᴰ : hom[ f ] xᴰ yᴰ)
             rel[ id-rel f ] fᴰ fᴰ

          transᴰ :  {x y}
             {f g h : hom x y}
             {r : rel f g}
             {s : rel g h}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             {fᴰ : hom[ f ] xᴰ yᴰ}
             {gᴰ : hom[ g ] xᴰ yᴰ}
             {hᴰ : hom[ h ] xᴰ yᴰ}
             (rᴰ : rel[ r ] fᴰ gᴰ)
             (sᴰ : rel[ s ] gᴰ hᴰ)
             rel[ trans r s ] fᴰ hᴰ

          comp-relᴰ :  {x y z}
             {f₁ f₂ : hom x y}
             {g₁ g₂ : hom y z}
             {r : rel f₁ f₂}
             {s : rel g₁ g₂}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]} {zᴰ : ob[ z ]}
             {f₁ᴰ : hom[ f₁ ] xᴰ yᴰ}
             {f₂ᴰ : hom[ f₂ ] xᴰ yᴰ}
             {g₁ᴰ : hom[ g₁ ] yᴰ zᴰ}
             {g₂ᴰ : hom[ g₂ ] yᴰ zᴰ}
             (rᴰ : rel[ r ] f₁ᴰ f₂ᴰ)
             (sᴰ : rel[ s ] g₁ᴰ g₂ᴰ)
             rel[ comp-rel r s ] (comp-homᴰ f₁ᴰ g₁ᴰ) (comp-homᴰ f₂ᴰ g₂ᴰ)

        _∙₁ᴰ_ = comp-homᴰ
        _∙ᵥᴰ_ = transᴰ
        _∙ₕᴰ_ = comp-relᴰ

      record IsTwoCategoryᴰ (sᴰ : TwoCategoryStrᴰ) : Type (ℓ-max ℓC ℓCᴰ) where
        no-eta-equality
        private
          open module sᴰ = TwoCategoryStrᴰ sᴰ

        field
          is-set-relᴰ : {x y : ob} {f g : hom x y} {s : rel f g}
             {xᴰ : ob[ x ]}
             {yᴰ : ob[ y ]}
             (fᴰ : hom[ f ] xᴰ yᴰ)
             (gᴰ : hom[ g ] xᴰ yᴰ)
             isSet (rel[ s ] fᴰ gᴰ)

        field
          trans-assocᴰ : {x y : ob}
             {f g h k : hom x y}
             {r : rel f g}
             {s : rel g h}
             {t : rel h k}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             {fᴰ : hom[ f ] xᴰ yᴰ}
             {gᴰ : hom[ g ] xᴰ yᴰ}
             {hᴰ : hom[ h ] xᴰ yᴰ}
             {kᴰ : hom[ k ] xᴰ yᴰ}
             (rᴰ : rel[ r ] fᴰ gᴰ)
             (sᴰ : rel[ s ] gᴰ hᴰ)
             (tᴰ : rel[ t ] hᴰ kᴰ)
             PathP  i  rel[ trans-assoc r s t i ] fᴰ kᴰ)
              ((rᴰ ∙ᵥᴰ sᴰ) ∙ᵥᴰ tᴰ)
              (rᴰ ∙ᵥᴰ (sᴰ ∙ᵥᴰ tᴰ))
          
          trans-unit-leftᴰ : {x y : ob}
             {f g : hom x y}
             {s : rel f g}
             {xᴰ : ob[ x ]}
             {yᴰ : ob[ y ]}
             {fᴰ : hom[ f ] xᴰ yᴰ}
             {gᴰ : hom[ g ] xᴰ yᴰ}
             (sᴰ : rel[ s ] fᴰ gᴰ)
             PathP  i  rel[ trans-unit-left s i ] fᴰ gᴰ)
              (id-relᴰ fᴰ ∙ᵥᴰ sᴰ)
              sᴰ

          trans-unit-rightᴰ : {x y : ob}
             {f g : hom x y}
             {r : rel f g}
             {xᴰ : ob[ x ]}
             {yᴰ : ob[ y ]}
             {fᴰ : hom[ f ] xᴰ yᴰ}
             {gᴰ : hom[ g ] xᴰ yᴰ}
             (rᴰ : rel[ r ] fᴰ gᴰ)
             PathP  i  rel[ trans-unit-right r i ] fᴰ gᴰ)
              (rᴰ ∙ᵥᴰ id-relᴰ gᴰ)
              rᴰ

        field
          comp-rel-idᴰ : {x y z : ob} {f : hom x y} {g : hom y z}
             {xᴰ : ob[ x ]}
             {yᴰ : ob[ y ]}
             {zᴰ : ob[ z ]}
             (fᴰ : hom[ f ] xᴰ yᴰ)
             (gᴰ : hom[ g ] yᴰ zᴰ)
             PathP  i  rel[ comp-rel-id f g i ] (fᴰ ∙₁ᴰ gᴰ) (fᴰ ∙₁ᴰ gᴰ))
              (id-relᴰ (fᴰ ∙₁ᴰ gᴰ))
              (id-relᴰ fᴰ ∙ₕᴰ id-relᴰ gᴰ)

          comp-rel-transᴰ : {x y z : ob} {f₁ f₂ f₃ : hom x y} {g₁ g₂ g₃ : hom y z}
             {s : rel f₁ f₂} {t : rel f₂ f₃} {u : rel g₁ g₂} {v : rel g₂ g₃}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]} {zᴰ : ob[ z ]}
             {f₁ᴰ : hom[ f₁ ] xᴰ yᴰ}
             {f₂ᴰ : hom[ f₂ ] xᴰ yᴰ}
             {f₃ᴰ : hom[ f₃ ] xᴰ yᴰ}
             {g₁ᴰ : hom[ g₁ ] yᴰ zᴰ}
             {g₂ᴰ : hom[ g₂ ] yᴰ zᴰ}
             {g₃ᴰ : hom[ g₃ ] yᴰ zᴰ}
             (sᴰ : rel[ s ] f₁ᴰ f₂ᴰ)
             (tᴰ : rel[ t ] f₂ᴰ f₃ᴰ)
             (uᴰ : rel[ u ] g₁ᴰ g₂ᴰ)
             (vᴰ : rel[ v ] g₂ᴰ g₃ᴰ)
             PathP  i  rel[ comp-rel-trans s t u v i ] (f₁ᴰ ∙₁ᴰ g₁ᴰ) (f₃ᴰ ∙₁ᴰ g₃ᴰ))
              ((sᴰ ∙ᵥᴰ tᴰ) ∙ₕᴰ (uᴰ ∙ᵥᴰ vᴰ))
              ((sᴰ ∙ₕᴰ uᴰ) ∙ᵥᴰ (tᴰ ∙ₕᴰ vᴰ))

        field
          comp-hom-assocᴰ : {x y z w : ob} {f : hom x y} {g : hom y z} {h : hom z w}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]} {zᴰ : ob[ z ]} {wᴰ : ob[ w ]}
             (fᴰ : hom[ f ] xᴰ yᴰ)
             (gᴰ : hom[ g ] yᴰ zᴰ)
             (hᴰ : hom[ h ] zᴰ wᴰ)
             PathP  i  hom[ C.comp-hom-assoc f g h i ] xᴰ wᴰ)
                ((fᴰ ∙₁ᴰ gᴰ) ∙₁ᴰ hᴰ)
                (fᴰ ∙₁ᴰ (gᴰ ∙₁ᴰ hᴰ))
          
          comp-hom-unit-leftᴰ : {x y : C.ob} {g : C.hom x y}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             (gᴰ : hom[ g ] xᴰ yᴰ)
             PathP  i  hom[ C.comp-hom-unit-left g i ] xᴰ yᴰ)
                (id-homᴰ xᴰ ∙₁ᴰ gᴰ)
                gᴰ

          comp-hom-unit-rightᴰ : {x y : C.ob} {f : C.hom x y}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             (fᴰ : hom[ f ] xᴰ yᴰ)
             PathP  i  hom[ C.comp-hom-unit-right f i ] xᴰ yᴰ)
                (fᴰ ∙₁ᴰ id-homᴰ yᴰ)
                fᴰ
        field
          comp-rel-assocᴰ : {x y z w : ob} {f₁ f₂ : hom x y} {g₁ g₂ : hom y z} {k₁ k₂ : hom z w}
             {s : rel f₁ f₂} {t : rel g₁ g₂} {u : rel k₁ k₂}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]} {zᴰ : ob[ z ]} {wᴰ : ob[ w ]}
             {f₁ᴰ : hom[ f₁ ] xᴰ yᴰ}
             {f₂ᴰ : hom[ f₂ ] xᴰ yᴰ}
             {g₁ᴰ : hom[ g₁ ] yᴰ zᴰ}
             {g₂ᴰ : hom[ g₂ ] yᴰ zᴰ}
             {k₁ᴰ : hom[ k₁ ] zᴰ wᴰ}
             {k₂ᴰ : hom[ k₂ ] zᴰ wᴰ}
             (sᴰ : rel[ s ] f₁ᴰ f₂ᴰ)
             (tᴰ : rel[ t ] g₁ᴰ g₂ᴰ)
             (uᴰ : rel[ u ] k₁ᴰ k₂ᴰ)
             PathP  i  rel[ comp-rel-assoc s t u i ] (comp-hom-assocᴰ f₁ᴰ g₁ᴰ k₁ᴰ i) (comp-hom-assocᴰ f₂ᴰ g₂ᴰ k₂ᴰ i))
              ((sᴰ ∙ₕᴰ tᴰ) ∙ₕᴰ uᴰ)
              (sᴰ ∙ₕᴰ (tᴰ ∙ₕᴰ uᴰ))

          comp-rel-unit-leftᴰ : {x y : ob} {f g : hom x y} {s : rel f g}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             {fᴰ : hom[ f ] xᴰ yᴰ}
             {gᴰ : hom[ g ] xᴰ yᴰ}
             (sᴰ : rel[ s ] fᴰ gᴰ)
             PathP  i  rel[ comp-rel-unit-left s i ] (comp-hom-unit-leftᴰ fᴰ i) (comp-hom-unit-leftᴰ gᴰ i))
              (id-relᴰ (id-homᴰ xᴰ) ∙ₕᴰ sᴰ)
              sᴰ

          comp-rel-unit-rightᴰ : {x y : ob} {f g : hom x y} {r : rel f g}
             {xᴰ : ob[ x ]} {yᴰ : ob[ y ]}
             {fᴰ : hom[ f ] xᴰ yᴰ}
             {gᴰ : hom[ g ] xᴰ yᴰ}
             (rᴰ : rel[ r ] fᴰ gᴰ)
             PathP  i  rel[ comp-rel-unit-right r i ] (comp-hom-unit-rightᴰ fᴰ i) (comp-hom-unit-rightᴰ gᴰ i))
              (rᴰ ∙ₕᴰ id-relᴰ (id-homᴰ yᴰ))
              rᴰ

  record TwoCategoryᴰ : Type (ℓ-max ℓC (ℓ-suc ℓCᴰ)) where
    no-eta-equality
    field
      ob[_] : C.ob  Type ℓoᴰ
      hom[_] : {x y : C.ob} (f : C.hom x y) (xᴰ : ob[ x ]) (yᴰ : ob[ y ])  Type ℓhᴰ
      rel[_] : {x y : C.ob} {f g : C.hom x y}
         {xᴰ : ob[ x ]}  {yᴰ : ob[ y ]}
         (s : C.rel f g)
         (fᴰ : hom[ f ] xᴰ yᴰ)
         (gᴰ : hom[ g ] xᴰ yᴰ)
         Type ℓrᴰ

    field
      two-category-structureᴰ : TwoCategoryStrᴰ ob[_] hom[_] rel[_]
      is-two-categoryᴰ : IsTwoCategoryᴰ ob[_] hom[_] rel[_] two-category-structureᴰ

    open TwoCategoryStrᴰ two-category-structureᴰ public
    open IsTwoCategoryᴰ is-two-categoryᴰ public


module TotalTwoCategory
  {ℓo ℓh ℓr} (C : TwoCategory ℓo ℓh ℓr)
  {ℓoᴰ ℓhᴰ ℓrᴰ : Level} (Cᴰ : TwoCategoryᴰ C ℓoᴰ ℓhᴰ ℓrᴰ)
  where

  private
    open module C = TwoCategory C
    open module Cᴰ = TwoCategoryᴰ Cᴰ

    ∫₀ : Type _
    ∫₀ = Σ ob ob[_]

    ∫₁ : (x y : ∫₀)  Type _
    ∫₁ (x , xᴰ) (y , yᴰ) = Σ[ f  hom x y ] hom[ f ] xᴰ yᴰ

    ∫₂ : {x y : ∫₀} (f g : ∫₁ x y)  Type _
    ∫₂ (f , fᴰ) (g , gᴰ) = Σ[ r  rel f g ] rel[ r ] fᴰ gᴰ

  ∫₁≡ : {x y : ∫₀} {f g : ∫₁ x y}
     (p : f .fst  g .fst)
     (pᴰ : PathP  i  hom[ p i ] (x .snd) (y .snd)) (f .snd) (g .snd))
     f  g
  ∫₁≡ p pᴰ i .fst = p i
  ∫₁≡ p pᴰ i .snd = pᴰ i

  ∫₂≡ : {x y : ∫₀} {f g : ∫₁ x y} {r s : ∫₂ f g}
     (p : r .fst  s .fst)
     (pᴰ : PathP  i  rel[ p i ] (f .snd) (g .snd)) (r .snd) (s .snd))
     r  s
  ∫₂≡ p pᴰ i .fst = p i
  ∫₂≡ p pᴰ i .snd = pᴰ i

  ∫-two-category-structure : TwoCategoryStr ∫₀ ∫₁ ∫₂
  ∫-two-category-structure .TwoCategoryStr.id-hom (x , xᴰ) = id-hom x , id-homᴰ xᴰ
  ∫-two-category-structure .TwoCategoryStr.comp-hom (f , fᴰ) (g , gᴰ) = (f ∙₁ g) , fᴰ ∙₁ᴰ gᴰ
  ∫-two-category-structure .TwoCategoryStr.id-rel (f , fᴰ) = id-rel f , id-relᴰ fᴰ
  ∫-two-category-structure .TwoCategoryStr.trans (r , rᴰ) (s , sᴰ) = r ∙ᵥ s , rᴰ ∙ᵥᴰ sᴰ
  ∫-two-category-structure .TwoCategoryStr.comp-rel (r , rᴰ) (s , sᴰ) = r ∙ₕ s , rᴰ ∙ₕᴰ sᴰ

  ∫-is-two-cat : IsTwoCategory ∫₀ ∫₁ ∫₂ ∫-two-category-structure
  ∫-is-two-cat .IsTwoCategory.is-set-rel (f , fᴰ) (g , gᴰ) = isSetΣ (is-set-rel f g) λ r  (is-set-relᴰ fᴰ gᴰ)
  ∫-is-two-cat .IsTwoCategory.trans-assoc (r , rᴰ) (s , sᴰ) (t , tᴰ) i .fst = trans-assoc r s t i
  ∫-is-two-cat .IsTwoCategory.trans-assoc (r , rᴰ) (s , sᴰ) (t , tᴰ) i .snd = trans-assocᴰ rᴰ sᴰ tᴰ i
  ∫-is-two-cat .IsTwoCategory.trans-unit-left (r , rᴰ) i .fst = trans-unit-left r i
  ∫-is-two-cat .IsTwoCategory.trans-unit-left (r , rᴰ) i .snd = trans-unit-leftᴰ rᴰ i
  ∫-is-two-cat .IsTwoCategory.trans-unit-right (r , rᴰ) i .fst = trans-unit-right r i
  ∫-is-two-cat .IsTwoCategory.trans-unit-right (r , rᴰ) i .snd = trans-unit-rightᴰ rᴰ i
  ∫-is-two-cat .IsTwoCategory.comp-rel-id (f , fᴰ) (g , gᴰ) i .fst = comp-rel-id f g i
  ∫-is-two-cat .IsTwoCategory.comp-rel-id (f , fᴰ) (g , gᴰ) i .snd = comp-rel-idᴰ fᴰ gᴰ i
  ∫-is-two-cat .IsTwoCategory.comp-rel-trans (s , sᴰ) (t , tᴰ) (u , uᴰ) (v , vᴰ) i .fst = comp-rel-trans s t u v i
  ∫-is-two-cat .IsTwoCategory.comp-rel-trans (s , sᴰ) (t , tᴰ) (u , uᴰ) (v , vᴰ) i .snd = comp-rel-transᴰ sᴰ tᴰ uᴰ vᴰ i
  ∫-is-two-cat .IsTwoCategory.comp-hom-assoc (f , fᴰ) (g , gᴰ) (h , hᴰ) = ∫₁≡ (comp-hom-assoc f g h) (comp-hom-assocᴰ fᴰ gᴰ hᴰ)
  ∫-is-two-cat .IsTwoCategory.comp-hom-unit-left (g , gᴰ) = ∫₁≡ (comp-hom-unit-left g) (comp-hom-unit-leftᴰ gᴰ)
  ∫-is-two-cat .IsTwoCategory.comp-hom-unit-right (f , fᴰ) = ∫₁≡ (comp-hom-unit-right f) (comp-hom-unit-rightᴰ fᴰ)
  ∫-is-two-cat .IsTwoCategory.comp-rel-assoc (s , sᴰ) (t , tᴰ) (u , uᴰ) i .fst = comp-rel-assoc s t u i
  ∫-is-two-cat .IsTwoCategory.comp-rel-assoc (s , sᴰ) (t , tᴰ) (u , uᴰ) i .snd = comp-rel-assocᴰ sᴰ tᴰ uᴰ i
  ∫-is-two-cat .IsTwoCategory.comp-rel-unit-left (s , sᴰ) i .fst = comp-rel-unit-left s i
  ∫-is-two-cat .IsTwoCategory.comp-rel-unit-left (s , sᴰ) i .snd = comp-rel-unit-leftᴰ sᴰ i
  ∫-is-two-cat .IsTwoCategory.comp-rel-unit-right (r , rᴰ) i .fst = comp-rel-unit-right r i
  ∫-is-two-cat .IsTwoCategory.comp-rel-unit-right (r , rᴰ) i .snd = comp-rel-unit-rightᴰ rᴰ i

   : TwoCategory (ℓ-max ℓo ℓoᴰ) (ℓ-max ℓh ℓhᴰ) (ℓ-max ℓr ℓrᴰ)
   .TwoCategory.ob = ∫₀
   .TwoCategory.hom = ∫₁
   .TwoCategory.rel = ∫₂
   .TwoCategory.two-category-structure = ∫-two-category-structure
   .TwoCategory.is-two-category = ∫-is-two-cat

  Fst : StrictFunctor  C
  Fst .StrictFunctor.F-ob = fst
  Fst .StrictFunctor.F-hom = fst
  Fst .StrictFunctor.F-rel = fst
  Fst .StrictFunctor.F-rel-id = refl
  Fst .StrictFunctor.F-rel-trans r s = refl
  Fst .StrictFunctor.F-hom-comp f g = refl
  Fst .StrictFunctor.F-hom-id x = refl
  Fst .StrictFunctor.F-assoc-filler-left f g h .fst = refl
  Fst .StrictFunctor.F-assoc-filler-left f g h .snd = reflSquare ((fst f ∙₁ fst g) ∙₁ fst h)
  Fst .StrictFunctor.F-assoc-filler-right f g h .fst = refl
  Fst .StrictFunctor.F-assoc-filler-right f g h .snd = reflSquare ((fst f) ∙₁ (fst g ∙₁ fst h))
  Fst .StrictFunctor.F-assoc f g h = λ i j  comp-hom-assoc (fst f) (fst g) (fst h) i
  Fst .StrictFunctor.F-unit-left-filler {x} f .fst = refl
  Fst .StrictFunctor.F-unit-left-filler {x} f .snd = reflSquare ((id-hom (fst x)) ∙₁ (fst f))
  Fst .StrictFunctor.F-unit-left f = λ i j  comp-hom-unit-left (fst f) i
  Fst .StrictFunctor.F-unit-right-filler {y} f .fst = refl
  Fst .StrictFunctor.F-unit-right-filler {y} f .snd = reflSquare ((fst f) ∙₁ (id-hom (fst y)))
  Fst .StrictFunctor.F-unit-right f = λ i j  comp-hom-unit-right (fst f) i